Loading drivers/media/platform/msm/camera/cam_core/cam_context.c +28 −5 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -196,6 +196,30 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx, return rc; } int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt) { int rc = 0; if (!ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.process_evt) { rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx, process_evt); } else { /* handling of this message is optional */ CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d", ctx->dev_hdl, ctx->state); } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { Loading Loading @@ -257,10 +281,10 @@ int cam_context_handle_release_dev(struct cam_context *ctx, int cam_context_handle_flush_dev(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { int rc; int rc = 0; if (!ctx->state_machine) { CAM_ERR(CAM_CORE, "context is not ready"); CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } Loading @@ -274,9 +298,8 @@ int cam_context_handle_flush_dev(struct cam_context *ctx, rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev( ctx, cmd); } else { CAM_ERR(CAM_CORE, "No flush device in dev %d, state %d", CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d", ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); Loading drivers/media/platform/msm/camera/cam_core/cam_context.h +16 −1 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -110,6 +110,7 @@ struct cam_ctx_ioctl_ops { * @unlink: Unlink the context * @apply_req: Apply setting for the context * @flush_req: Flush request to remove request ids * @process_evt: Handle event notification from CRM.(optional) * */ struct cam_ctx_crm_ops { Loading @@ -123,6 +124,8 @@ struct cam_ctx_crm_ops { struct cam_req_mgr_apply_request *apply); int (*flush_req)(struct cam_context *ctx, struct cam_req_mgr_flush_request *flush); int (*process_evt)(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *evt_data); }; Loading Loading @@ -272,6 +275,18 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, int cam_context_handle_crm_flush_req(struct cam_context *ctx, struct cam_req_mgr_flush_request *apply); /** * cam_context_handle_crm_process_evt() * * @brief: Handle process event command * * @ctx: Object pointer for cam_context * @process_evt: process event command payload * */ int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt); /** * cam_context_handle_acquire_dev() * Loading drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +65 −18 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -430,6 +430,8 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) uint32_t i; int rc = 0; CAM_DBG(CAM_CTXT, "E: NRT flush ctx"); /* * flush pending requests, take the sync lock to synchronize with the * sync callback thread so that the sync cb thread does not try to Loading @@ -444,23 +446,33 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) while (!list_empty(&temp_list)) { req = list_first_entry(&temp_list, struct cam_ctx_request, list); list_del_init(&req->list); req->flushed = 1; flush_args.flush_req_pending[flush_args.num_req_pending++] = req->req_priv; for (i = 0; i < req->num_out_map_entries; i++) if (req->out_map_entries[i].sync_id != -1) cam_sync_signal(req->out_map_entries[i].sync_id, if (req->out_map_entries[i].sync_id != -1) { rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled, sync_id:%d", req->request_id, req->out_map_entries[i]. sync_id); break; } } } mutex_unlock(&ctx->sync_mutex); if (ctx->hw_mgr_intf->hw_flush) { flush_args.num_req_active = 0; spin_lock(&ctx->lock); INIT_LIST_HEAD(&temp_list); list_splice_init(&ctx->active_req_list, &temp_list); list_for_each_entry(req, &temp_list, list) { list_for_each_entry(req, &ctx->active_req_list, list) { flush_args.flush_req_active[flush_args.num_req_active++] = req->req_priv; } Loading @@ -474,14 +486,31 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) } } INIT_LIST_HEAD(&temp_list); spin_lock(&ctx->lock); list_splice_init(&ctx->active_req_list, &temp_list); INIT_LIST_HEAD(&ctx->active_req_list); spin_unlock(&ctx->lock); while (!list_empty(&temp_list)) { req = list_first_entry(&temp_list, struct cam_ctx_request, list); list_del_init(&req->list); for (i = 0; i < req->num_out_map_entries; i++) for (i = 0; i < req->num_out_map_entries; i++) { if (req->out_map_entries[i].sync_id != -1) { cam_sync_signal(req->out_map_entries[i].sync_id, rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d", req->request_id, req->ctx, req->ctx->dev_name, req->ctx->dev_hdl, req->ctx->state); break; } } } spin_lock(&ctx->lock); Loading @@ -489,9 +518,10 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) spin_unlock(&ctx->lock); req->ctx = NULL; } INIT_LIST_HEAD(&ctx->active_req_list); return rc; CAM_DBG(CAM_CTXT, "X: NRT flush ctx"); return 0; } int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, Loading @@ -502,6 +532,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, uint32_t i; int rc = 0; CAM_DBG(CAM_CTXT, "E: NRT flush req"); flush_args.num_req_pending = 0; flush_args.num_req_active = 0; mutex_lock(&ctx->sync_mutex); Loading @@ -510,7 +542,9 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req->request_id != cmd->req_id) continue; list_del_init(&req->list); req->flushed = 1; flush_args.flush_req_pending[flush_args.num_req_pending++] = req->req_priv; break; Loading @@ -525,6 +559,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req->request_id != cmd->req_id) continue; list_del_init(&req->list); flush_args.flush_req_active[ flush_args.num_req_active++] = req->req_priv; Loading @@ -543,20 +579,31 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req) { if (flush_args.num_req_pending || flush_args.num_req_active) { list_del_init(&req->list); for (i = 0; i < req->num_out_map_entries; i++) if (req->out_map_entries[i].sync_id != -1) cam_sync_signal( if (req->out_map_entries[i].sync_id != -1) { rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled, sync_id:%d", req->request_id, req->out_map_entries[i]. sync_id); break; } } if (flush_args.num_req_active) { spin_lock(&ctx->lock); list_add_tail(&req->list, &ctx->free_req_list); spin_unlock(&ctx->lock); req->ctx = NULL; } } } CAM_DBG(CAM_CTXT, "X: NRT flush req"); return rc; return 0; } int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, Loading drivers/media/platform/msm/camera/cam_core/cam_node.c +22 −2 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -220,7 +220,7 @@ static int __cam_node_handle_flush_dev(struct cam_node *node, rc = cam_context_handle_flush_dev(ctx, flush); if (rc) CAM_ERR(CAM_CORE, "FLush failure for node %s", node->name); CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name); return rc; } Loading Loading @@ -342,6 +342,25 @@ static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush) return cam_context_handle_crm_flush_req(ctx, flush); } static int __cam_node_crm_process_evt( struct cam_req_mgr_link_evt_data *evt_data) { struct cam_context *ctx = NULL; if (!evt_data) { CAM_ERR(CAM_CORE, "Invalid process event request payload"); return -EINVAL; } ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl); if (!ctx) { CAM_ERR(CAM_CORE, "Can not get context for handle %d", evt_data->dev_hdl); return -EINVAL; } return cam_context_handle_crm_process_evt(ctx, evt_data); } int cam_node_deinit(struct cam_node *node) { if (node) Loading Loading @@ -394,6 +413,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info; node->crm_node_intf.link_setup = __cam_node_crm_link_setup; node->crm_node_intf.flush_req = __cam_node_crm_flush_req; node->crm_node_intf.process_evt = __cam_node_crm_process_evt; mutex_init(&node->list_mutex); INIT_LIST_HEAD(&node->free_ctx_list); Loading drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +70 −17 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -16,12 +16,19 @@ #include <linux/msm-bus.h> #include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/module.h> #include "cam_cpas_hw.h" #include "cam_cpas_hw_intf.h" #include "cam_cpas_soc.h" #define CAM_CPAS_AXI_MIN_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L) static uint cam_min_camnoc_ib_bw; module_param(cam_min_camnoc_ib_bw, uint, 0644); int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info) Loading Loading @@ -84,11 +91,19 @@ static int cam_cpas_util_vote_bus_client_level( } static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib) struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, bool camnoc_bw) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; int idx = 0; uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; if (cam_min_camnoc_ib_bw > 0) min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L; CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu", cam_min_camnoc_ib_bw, min_camnoc_ib_bw); if (!bus_client->valid) { CAM_ERR(CAM_CPAS, "bus client not valid"); Loading Loading @@ -118,11 +133,19 @@ static int cam_cpas_util_vote_bus_client_bw( bus_client->curr_vote_level = idx; mutex_unlock(&bus_client->lock); if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_BW)) ab = CAM_CPAS_AXI_MIN_BW; if (camnoc_bw == true) { if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW)) ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW; if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_BW)) ib = CAM_CPAS_AXI_MIN_BW; if ((ib > 0) && (ib < min_camnoc_ib_bw)) ib = min_camnoc_ib_bw; } else { if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW)) ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW; if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW)) ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; } pdata = bus_client->pdata; path = &(pdata->usecase[idx]); Loading Loading @@ -205,7 +228,7 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0); cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); else cam_cpas_util_vote_bus_client_level(bus_client, 0); Loading Loading @@ -370,7 +393,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, list_for_each_entry_safe(curr_port, temp_port, &cpas_core->axi_ports_list_head, sibling_port) { rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus, mnoc_bw, mnoc_bw); mnoc_bw, mnoc_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", Loading @@ -380,13 +403,13 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, if (soc_private->axi_camnoc_based) { cam_cpas_util_vote_bus_client_bw( &curr_port->camnoc_bus, 0, camnoc_bw); &curr_port->camnoc_bus, 0, camnoc_bw, true); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, %d", enable, rc); cam_cpas_util_vote_bus_client_bw( &curr_port->mnoc_bus, 0, 0); &curr_port->mnoc_bus, 0, 0, false); goto remove_ahb_vote; } } Loading Loading @@ -571,7 +594,7 @@ static int cam_cpas_util_apply_client_axi_vote( camnoc_bw, mnoc_bw); rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, mnoc_bw, mnoc_bw); mnoc_bw, mnoc_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", Loading @@ -581,7 +604,7 @@ static int cam_cpas_util_apply_client_axi_vote( if (soc_private->axi_camnoc_based) { rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus, 0, camnoc_bw); 0, camnoc_bw, true); if (rc) { CAM_ERR(CAM_CPAS, "Failed camnoc vote ab[%llu] ib[%llu] rc=%d", Loading Loading @@ -880,9 +903,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, goto done; if (cpas_core->streamon_clients == 0) { atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, applied_level); if (rc) { atomic_set(&cpas_core->irq_count, 0); CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); goto done; } Loading @@ -890,14 +915,17 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (cpas_core->internal_ops.power_on) { rc = cpas_core->internal_ops.power_on(cpas_hw); if (rc) { atomic_set(&cpas_core->irq_count, 0); cam_cpas_soc_disable_resources( &cpas_hw->soc_info); &cpas_hw->soc_info, true, true); CAM_ERR(CAM_CPAS, "failed in power_on settings rc=%d", rc); goto done; } } CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); cpas_hw->hw_state = CAM_HW_STATE_POWER_UP; } Loading @@ -912,6 +940,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, return rc; } static int _check_irq_count(struct cam_cpas *cpas_core) { return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1; } static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size) Loading @@ -924,6 +956,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote; int rc = 0; long result; if (!hw_priv || !stop_args) { CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", Loading Loading @@ -972,11 +1005,29 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, } } rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info); rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info); if (rc) { CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc); goto done; } /* Wait for any IRQs still being handled */ atomic_dec(&cpas_core->irq_count); result = wait_event_timeout(cpas_core->irq_count_wq, _check_irq_count(cpas_core), HZ); if (result == 0) { CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d", atomic_read(&cpas_core->irq_count)); } rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, false); if (rc) { CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc); goto done; } CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n", atomic_read(&cpas_core->irq_count)); cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; } Loading Loading @@ -1427,6 +1478,8 @@ int cam_cpas_hw_probe(struct platform_device *pdev, soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; cpas_core->num_clients = soc_private->num_clients; atomic_set(&cpas_core->irq_count, 0); init_waitqueue_head(&cpas_core->irq_count_wq); if (internal_ops->setup_regbase) { rc = internal_ops->setup_regbase(&cpas_hw->soc_info, Loading Loading @@ -1482,7 +1535,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev, if (rc) goto disable_soc_res; rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info); rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); if (rc) { CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc); goto remove_default_vote; Loading @@ -1500,7 +1553,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev, return 0; disable_soc_res: cam_cpas_soc_disable_resources(&cpas_hw->soc_info); cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); remove_default_vote: cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); axi_cleanup: Loading Loading
drivers/media/platform/msm/camera/cam_core/cam_context.c +28 −5 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -196,6 +196,30 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx, return rc; } int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt) { int rc = 0; if (!ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].crm_ops.process_evt) { rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx, process_evt); } else { /* handling of this message is optional */ CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d", ctx->dev_hdl, ctx->state); } mutex_unlock(&ctx->ctx_mutex); return rc; } int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { Loading Loading @@ -257,10 +281,10 @@ int cam_context_handle_release_dev(struct cam_context *ctx, int cam_context_handle_flush_dev(struct cam_context *ctx, struct cam_flush_dev_cmd *cmd) { int rc; int rc = 0; if (!ctx->state_machine) { CAM_ERR(CAM_CORE, "context is not ready"); CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } Loading @@ -274,9 +298,8 @@ int cam_context_handle_flush_dev(struct cam_context *ctx, rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev( ctx, cmd); } else { CAM_ERR(CAM_CORE, "No flush device in dev %d, state %d", CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d", ctx->dev_hdl, ctx->state); rc = -EPROTO; } mutex_unlock(&ctx->ctx_mutex); Loading
drivers/media/platform/msm/camera/cam_core/cam_context.h +16 −1 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -110,6 +110,7 @@ struct cam_ctx_ioctl_ops { * @unlink: Unlink the context * @apply_req: Apply setting for the context * @flush_req: Flush request to remove request ids * @process_evt: Handle event notification from CRM.(optional) * */ struct cam_ctx_crm_ops { Loading @@ -123,6 +124,8 @@ struct cam_ctx_crm_ops { struct cam_req_mgr_apply_request *apply); int (*flush_req)(struct cam_context *ctx, struct cam_req_mgr_flush_request *flush); int (*process_evt)(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *evt_data); }; Loading Loading @@ -272,6 +275,18 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, int cam_context_handle_crm_flush_req(struct cam_context *ctx, struct cam_req_mgr_flush_request *apply); /** * cam_context_handle_crm_process_evt() * * @brief: Handle process event command * * @ctx: Object pointer for cam_context * @process_evt: process event command payload * */ int cam_context_handle_crm_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *process_evt); /** * cam_context_handle_acquire_dev() * Loading
drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +65 −18 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -430,6 +430,8 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) uint32_t i; int rc = 0; CAM_DBG(CAM_CTXT, "E: NRT flush ctx"); /* * flush pending requests, take the sync lock to synchronize with the * sync callback thread so that the sync cb thread does not try to Loading @@ -444,23 +446,33 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) while (!list_empty(&temp_list)) { req = list_first_entry(&temp_list, struct cam_ctx_request, list); list_del_init(&req->list); req->flushed = 1; flush_args.flush_req_pending[flush_args.num_req_pending++] = req->req_priv; for (i = 0; i < req->num_out_map_entries; i++) if (req->out_map_entries[i].sync_id != -1) cam_sync_signal(req->out_map_entries[i].sync_id, if (req->out_map_entries[i].sync_id != -1) { rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled, sync_id:%d", req->request_id, req->out_map_entries[i]. sync_id); break; } } } mutex_unlock(&ctx->sync_mutex); if (ctx->hw_mgr_intf->hw_flush) { flush_args.num_req_active = 0; spin_lock(&ctx->lock); INIT_LIST_HEAD(&temp_list); list_splice_init(&ctx->active_req_list, &temp_list); list_for_each_entry(req, &temp_list, list) { list_for_each_entry(req, &ctx->active_req_list, list) { flush_args.flush_req_active[flush_args.num_req_active++] = req->req_priv; } Loading @@ -474,14 +486,31 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) } } INIT_LIST_HEAD(&temp_list); spin_lock(&ctx->lock); list_splice_init(&ctx->active_req_list, &temp_list); INIT_LIST_HEAD(&ctx->active_req_list); spin_unlock(&ctx->lock); while (!list_empty(&temp_list)) { req = list_first_entry(&temp_list, struct cam_ctx_request, list); list_del_init(&req->list); for (i = 0; i < req->num_out_map_entries; i++) for (i = 0; i < req->num_out_map_entries; i++) { if (req->out_map_entries[i].sync_id != -1) { cam_sync_signal(req->out_map_entries[i].sync_id, rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d", req->request_id, req->ctx, req->ctx->dev_name, req->ctx->dev_hdl, req->ctx->state); break; } } } spin_lock(&ctx->lock); Loading @@ -489,9 +518,10 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) spin_unlock(&ctx->lock); req->ctx = NULL; } INIT_LIST_HEAD(&ctx->active_req_list); return rc; CAM_DBG(CAM_CTXT, "X: NRT flush ctx"); return 0; } int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, Loading @@ -502,6 +532,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, uint32_t i; int rc = 0; CAM_DBG(CAM_CTXT, "E: NRT flush req"); flush_args.num_req_pending = 0; flush_args.num_req_active = 0; mutex_lock(&ctx->sync_mutex); Loading @@ -510,7 +542,9 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req->request_id != cmd->req_id) continue; list_del_init(&req->list); req->flushed = 1; flush_args.flush_req_pending[flush_args.num_req_pending++] = req->req_priv; break; Loading @@ -525,6 +559,8 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req->request_id != cmd->req_id) continue; list_del_init(&req->list); flush_args.flush_req_active[ flush_args.num_req_active++] = req->req_priv; Loading @@ -543,20 +579,31 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, if (req) { if (flush_args.num_req_pending || flush_args.num_req_active) { list_del_init(&req->list); for (i = 0; i < req->num_out_map_entries; i++) if (req->out_map_entries[i].sync_id != -1) cam_sync_signal( if (req->out_map_entries[i].sync_id != -1) { rc = cam_sync_signal( req->out_map_entries[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc == -EALREADY) { CAM_ERR(CAM_CTXT, "Req: %llu already signalled, sync_id:%d", req->request_id, req->out_map_entries[i]. sync_id); break; } } if (flush_args.num_req_active) { spin_lock(&ctx->lock); list_add_tail(&req->list, &ctx->free_req_list); spin_unlock(&ctx->lock); req->ctx = NULL; } } } CAM_DBG(CAM_CTXT, "X: NRT flush req"); return rc; return 0; } int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, Loading
drivers/media/platform/msm/camera/cam_core/cam_node.c +22 −2 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -220,7 +220,7 @@ static int __cam_node_handle_flush_dev(struct cam_node *node, rc = cam_context_handle_flush_dev(ctx, flush); if (rc) CAM_ERR(CAM_CORE, "FLush failure for node %s", node->name); CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name); return rc; } Loading Loading @@ -342,6 +342,25 @@ static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush) return cam_context_handle_crm_flush_req(ctx, flush); } static int __cam_node_crm_process_evt( struct cam_req_mgr_link_evt_data *evt_data) { struct cam_context *ctx = NULL; if (!evt_data) { CAM_ERR(CAM_CORE, "Invalid process event request payload"); return -EINVAL; } ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl); if (!ctx) { CAM_ERR(CAM_CORE, "Can not get context for handle %d", evt_data->dev_hdl); return -EINVAL; } return cam_context_handle_crm_process_evt(ctx, evt_data); } int cam_node_deinit(struct cam_node *node) { if (node) Loading Loading @@ -394,6 +413,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info; node->crm_node_intf.link_setup = __cam_node_crm_link_setup; node->crm_node_intf.flush_req = __cam_node_crm_flush_req; node->crm_node_intf.process_evt = __cam_node_crm_process_evt; mutex_init(&node->list_mutex); INIT_LIST_HEAD(&node->free_ctx_list); Loading
drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +70 −17 Original line number Diff line number Diff line /* Copyright (c) 2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -16,12 +16,19 @@ #include <linux/msm-bus.h> #include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/module.h> #include "cam_cpas_hw.h" #include "cam_cpas_hw_intf.h" #include "cam_cpas_soc.h" #define CAM_CPAS_AXI_MIN_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) #define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L) static uint cam_min_camnoc_ib_bw; module_param(cam_min_camnoc_ib_bw, uint, 0644); int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info) Loading Loading @@ -84,11 +91,19 @@ static int cam_cpas_util_vote_bus_client_level( } static int cam_cpas_util_vote_bus_client_bw( struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib) struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, bool camnoc_bw) { struct msm_bus_paths *path; struct msm_bus_scale_pdata *pdata; int idx = 0; uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; if (cam_min_camnoc_ib_bw > 0) min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L; CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu", cam_min_camnoc_ib_bw, min_camnoc_ib_bw); if (!bus_client->valid) { CAM_ERR(CAM_CPAS, "bus client not valid"); Loading Loading @@ -118,11 +133,19 @@ static int cam_cpas_util_vote_bus_client_bw( bus_client->curr_vote_level = idx; mutex_unlock(&bus_client->lock); if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_BW)) ab = CAM_CPAS_AXI_MIN_BW; if (camnoc_bw == true) { if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW)) ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW; if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_BW)) ib = CAM_CPAS_AXI_MIN_BW; if ((ib > 0) && (ib < min_camnoc_ib_bw)) ib = min_camnoc_ib_bw; } else { if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW)) ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW; if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW)) ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; } pdata = bus_client->pdata; path = &(pdata->usecase[idx]); Loading Loading @@ -205,7 +228,7 @@ static int cam_cpas_util_unregister_bus_client( return -EINVAL; if (bus_client->dyn_vote) cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0); cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); else cam_cpas_util_vote_bus_client_level(bus_client, 0); Loading Loading @@ -370,7 +393,7 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, list_for_each_entry_safe(curr_port, temp_port, &cpas_core->axi_ports_list_head, sibling_port) { rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus, mnoc_bw, mnoc_bw); mnoc_bw, mnoc_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, rc=%d", Loading @@ -380,13 +403,13 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, if (soc_private->axi_camnoc_based) { cam_cpas_util_vote_bus_client_bw( &curr_port->camnoc_bus, 0, camnoc_bw); &curr_port->camnoc_bus, 0, camnoc_bw, true); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote, enable=%d, %d", enable, rc); cam_cpas_util_vote_bus_client_bw( &curr_port->mnoc_bus, 0, 0); &curr_port->mnoc_bus, 0, 0, false); goto remove_ahb_vote; } } Loading Loading @@ -571,7 +594,7 @@ static int cam_cpas_util_apply_client_axi_vote( camnoc_bw, mnoc_bw); rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, mnoc_bw, mnoc_bw); mnoc_bw, mnoc_bw, false); if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", Loading @@ -581,7 +604,7 @@ static int cam_cpas_util_apply_client_axi_vote( if (soc_private->axi_camnoc_based) { rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus, 0, camnoc_bw); 0, camnoc_bw, true); if (rc) { CAM_ERR(CAM_CPAS, "Failed camnoc vote ab[%llu] ib[%llu] rc=%d", Loading Loading @@ -880,9 +903,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, goto done; if (cpas_core->streamon_clients == 0) { atomic_set(&cpas_core->irq_count, 1); rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, applied_level); if (rc) { atomic_set(&cpas_core->irq_count, 0); CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); goto done; } Loading @@ -890,14 +915,17 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, if (cpas_core->internal_ops.power_on) { rc = cpas_core->internal_ops.power_on(cpas_hw); if (rc) { atomic_set(&cpas_core->irq_count, 0); cam_cpas_soc_disable_resources( &cpas_hw->soc_info); &cpas_hw->soc_info, true, true); CAM_ERR(CAM_CPAS, "failed in power_on settings rc=%d", rc); goto done; } } CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); cpas_hw->hw_state = CAM_HW_STATE_POWER_UP; } Loading @@ -912,6 +940,10 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args, return rc; } static int _check_irq_count(struct cam_cpas *cpas_core) { return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1; } static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size) Loading @@ -924,6 +956,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, struct cam_ahb_vote ahb_vote; struct cam_axi_vote axi_vote; int rc = 0; long result; if (!hw_priv || !stop_args) { CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", Loading Loading @@ -972,11 +1005,29 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, } } rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info); rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info); if (rc) { CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc); goto done; } /* Wait for any IRQs still being handled */ atomic_dec(&cpas_core->irq_count); result = wait_event_timeout(cpas_core->irq_count_wq, _check_irq_count(cpas_core), HZ); if (result == 0) { CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d", atomic_read(&cpas_core->irq_count)); } rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, false); if (rc) { CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc); goto done; } CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n", atomic_read(&cpas_core->irq_count)); cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; } Loading Loading @@ -1427,6 +1478,8 @@ int cam_cpas_hw_probe(struct platform_device *pdev, soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; cpas_core->num_clients = soc_private->num_clients; atomic_set(&cpas_core->irq_count, 0); init_waitqueue_head(&cpas_core->irq_count_wq); if (internal_ops->setup_regbase) { rc = internal_ops->setup_regbase(&cpas_hw->soc_info, Loading Loading @@ -1482,7 +1535,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev, if (rc) goto disable_soc_res; rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info); rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); if (rc) { CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc); goto remove_default_vote; Loading @@ -1500,7 +1553,7 @@ int cam_cpas_hw_probe(struct platform_device *pdev, return 0; disable_soc_res: cam_cpas_soc_disable_resources(&cpas_hw->soc_info); cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); remove_default_vote: cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); axi_cleanup: Loading