diff --git a/drivers/Makefile b/drivers/Makefile index a59a49ce1be5..01e4e572c8bf 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -49,6 +49,14 @@ ifdef CONFIG_QCOM_CX_IPEAK camera-y += cam_utils/cam_cx_ipeak.o endif +ifneq (,$(filter $(CONFIG_QCOM_BUS_SCALING),y m)) +camera-y += cam_utils/cam_soc_bus.o +endif + +ifneq (,$(filter $(CONFIG_INTERCONNECT_QCOM),y m)) +camera-y += cam_utils/cam_soc_icc.o +endif + camera-$(CONFIG_SPECTRA_ISP) += \ cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.o \ cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.o \ diff --git a/drivers/cam_cpas/cam_cpas_hw.c b/drivers/cam_cpas/cam_cpas_hw.c index ae0368acdb05..061d2594421a 100644 --- a/drivers/cam_cpas/cam_cpas_hw.c +++ b/drivers/cam_cpas/cam_cpas_hw.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -56,73 +55,54 @@ int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, static int cam_cpas_util_vote_bus_client_level( struct cam_cpas_bus_client *bus_client, unsigned int level) { - if (!bus_client->valid || (bus_client->dyn_vote == true)) { - CAM_ERR(CAM_CPAS, "Invalid params %d %d", bus_client->valid, - bus_client->dyn_vote); - return -EINVAL; - } + int rc = 0; - if (level >= bus_client->num_usecases) { - CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level, - bus_client->num_usecases); - return -EINVAL; + if (!bus_client->valid) { + CAM_ERR(CAM_CPAS, "bus client not valid"); + rc = -EINVAL; + goto end; } if (level == bus_client->curr_vote_level) - return 0; + goto end; - CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] index[%d]", - bus_client->client_id, bus_client->name, level); - msm_bus_scale_client_update_request(bus_client->client_id, level); + rc = cam_soc_bus_client_update_request(bus_client->soc_bus_client, + level); + if (rc) { + CAM_ERR(CAM_CPAS, "Client: %s update request failed rc: %d", + bus_client->common_data.name, rc); + goto end; + } bus_client->curr_vote_level = level; - return 0; +end: + return rc; } static int cam_cpas_util_vote_bus_client_bw( 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; + int rc = 0; uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + if (!bus_client->valid) { + CAM_ERR(CAM_CPAS, "bus client: %s not valid", + bus_client->common_data.name); + rc = -EINVAL; + goto end; + } + 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"); - return -EINVAL; - } - - if ((bus_client->num_usecases != 2) || - (bus_client->num_paths != 1) || - (bus_client->dyn_vote != true)) { - CAM_ERR(CAM_CPAS, "dynamic update not allowed %d %d %d", - bus_client->num_usecases, bus_client->num_paths, - bus_client->dyn_vote); - return -EINVAL; - } + CAM_DBG(CAM_CPAS, + "Bus_client: %s, cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu", + bus_client->common_data.name, cam_min_camnoc_ib_bw, + min_camnoc_ib_bw); mutex_lock(&bus_client->lock); - - if (bus_client->curr_vote_level > 1) { - CAM_ERR(CAM_CPAS, "curr_vote_level %d cannot be greater than 1", - bus_client->curr_vote_level); - mutex_unlock(&bus_client->lock); - return -EINVAL; - } - - idx = bus_client->curr_vote_level; - idx = 1 - idx; - bus_client->curr_vote_level = idx; - mutex_unlock(&bus_client->lock); - - if (camnoc_bw == true) { + if (camnoc_bw) { if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW)) ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW; @@ -136,96 +116,51 @@ static int cam_cpas_util_vote_bus_client_bw( ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; } - pdata = bus_client->pdata; - path = &(pdata->usecase[idx]); - path->vectors[0].ab = ab; - path->vectors[0].ib = ib; + rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib); + if (rc) { + CAM_ERR(CAM_CPAS, + "Update bw failed, ab[%llu] ib[%llu]", + ab, ib); + goto unlock_client; + } - CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", - bus_client->client_id, bus_client->name, ab, ib, idx); - msm_bus_scale_client_update_request(bus_client->client_id, idx); - - return 0; +unlock_client: + mutex_unlock(&bus_client->lock); +end: + return rc; } static int cam_cpas_util_register_bus_client( struct cam_hw_soc_info *soc_info, struct device_node *dev_node, struct cam_cpas_bus_client *bus_client) { - struct msm_bus_scale_pdata *pdata = NULL; - uint32_t client_id; - int rc; + int rc = 0; - pdata = msm_bus_pdata_from_node(soc_info->pdev, - dev_node); - if (!pdata) { - CAM_ERR(CAM_CPAS, "failed get_pdata"); - return -EINVAL; + rc = cam_soc_bus_client_register(soc_info->pdev, dev_node, + &bus_client->soc_bus_client, &bus_client->common_data); + if (rc) { + CAM_ERR(CAM_CPAS, "Bus client: %s registertion failed ,rc: %d", + bus_client->common_data.name, rc); + return rc; } - - if ((pdata->num_usecases == 0) || - (pdata->usecase[0].num_paths == 0)) { - CAM_ERR(CAM_CPAS, "usecase=%d", pdata->num_usecases); - rc = -EINVAL; - goto error; - } - - client_id = msm_bus_scale_register_client(pdata); - if (!client_id) { - CAM_ERR(CAM_CPAS, "failed in register ahb bus client"); - rc = -EINVAL; - goto error; - } - - bus_client->dyn_vote = of_property_read_bool(dev_node, - "qcom,msm-bus-vector-dyn-vote"); - - if (bus_client->dyn_vote && (pdata->num_usecases != 2)) { - CAM_ERR(CAM_CPAS, "Excess or less vectors %d", - pdata->num_usecases); - rc = -EINVAL; - goto fail_unregister_client; - } - - msm_bus_scale_client_update_request(client_id, 0); - - bus_client->src = pdata->usecase[0].vectors[0].src; - bus_client->dst = pdata->usecase[0].vectors[0].dst; - bus_client->pdata = pdata; - bus_client->client_id = client_id; - bus_client->num_usecases = pdata->num_usecases; - bus_client->num_paths = pdata->usecase[0].num_paths; bus_client->curr_vote_level = 0; bus_client->valid = true; - bus_client->name = pdata->name; mutex_init(&bus_client->lock); - CAM_DBG(CAM_CPAS, "Bus Client=[%d][%s] : src=%d, dst=%d", - bus_client->client_id, bus_client->name, - bus_client->src, bus_client->dst); - return 0; -fail_unregister_client: - msm_bus_scale_unregister_client(bus_client->client_id); -error: - return rc; - } static int cam_cpas_util_unregister_bus_client( struct cam_cpas_bus_client *bus_client) { - if (!bus_client->valid) + if (!bus_client->valid) { + CAM_ERR(CAM_CPAS, "bus client not valid"); return -EINVAL; + } - if (bus_client->dyn_vote) - cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); - else - cam_cpas_util_vote_bus_client_level(bus_client, 0); - - msm_bus_scale_unregister_client(bus_client->client_id); + cam_soc_bus_client_unregister(&bus_client->soc_bus_client); + bus_client->curr_vote_level = 0; bus_client->valid = false; - mutex_destroy(&bus_client->lock); return 0; @@ -765,7 +700,7 @@ vote_start_clients: continue; CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", - axi_port->axi_port_name, axi_port->ab_bw, + axi_port->bus_client.common_data.name, axi_port->ab_bw, axi_port->ib_bw, axi_port->additional_bw); if (axi_port->ab_bw) @@ -920,9 +855,9 @@ static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, mutex_lock(&ahb_bus_client->lock); cpas_client->ahb_level = required_level; - CAM_DBG(CAM_CPAS, "Client=[%d][%s] required level[%d], curr_level[%d]", - ahb_bus_client->client_id, ahb_bus_client->name, - required_level, ahb_bus_client->curr_vote_level); + CAM_DBG(CAM_CPAS, "Client[%s] required level[%d], curr_level[%d]", + ahb_bus_client->common_data.name, required_level, + ahb_bus_client->curr_vote_level); if (required_level == ahb_bus_client->curr_vote_level) goto unlock_bus_client; diff --git a/drivers/cam_cpas/cam_cpas_hw.h b/drivers/cam_cpas/cam_cpas_hw.h index b3c01b3ee737..2b207a090a02 100644 --- a/drivers/cam_cpas/cam_cpas_hw.h +++ b/drivers/cam_cpas/cam_cpas_hw.h @@ -10,6 +10,7 @@ #include "cam_cpas_api.h" #include "cam_cpas_hw_intf.h" #include "cam_common_util.h" +#include "cam_soc_bus.h" #define CAM_CPAS_INFLIGHT_WORKS 5 #define CAM_CPAS_MAX_CLIENTS 40 @@ -117,37 +118,24 @@ struct cam_cpas_client { /** * struct cam_cpas_bus_client : Bus client information * - * @src: Bus master/src id - * @dst: Bus slave/dst id - * @pdata: Bus pdata information - * @client_id: Bus client id - * @num_usecases: Number of use cases for this client - * @num_paths: Number of paths for this client - * @curr_vote_level: current voted index - * @dyn_vote: Whether dynamic voting enabled - * @lock: Mutex lock used while voting on this client * @valid: Whether bus client is valid * @name: Name of the bus client - * + * @lock: Mutex lock used while voting on this client + * @curr_vote_level: current voted index + * @common_data: Common data fields for bus client + * @soc_bus_client: Bus client private information */ struct cam_cpas_bus_client { - int src; - int dst; - struct msm_bus_scale_pdata *pdata; - uint32_t client_id; - int num_usecases; - int num_paths; - unsigned int curr_vote_level; - bool dyn_vote; - struct mutex lock; bool valid; - const char *name; + struct mutex lock; + unsigned int curr_vote_level; + struct cam_soc_bus_client_common_data common_data; + void *soc_bus_client; }; /** * struct cam_cpas_axi_port : AXI port information * - * @axi_port_name: Name of this AXI port * @bus_client: bus client info for this port * @ib_bw_voting_needed: if this port can update ib bw dynamically * @axi_port_node: Node representing AXI Port info in device tree @@ -156,7 +144,6 @@ struct cam_cpas_bus_client { * @additional_bw: Additional bandwidth to cover non-hw cpas clients */ struct cam_cpas_axi_port { - const char *axi_port_name; struct cam_cpas_bus_client bus_client; bool ib_bw_voting_needed; struct device_node *axi_port_node; diff --git a/drivers/cam_cpas/cam_cpas_soc.c b/drivers/cam_cpas/cam_cpas_soc.c index c86753dd24d9..b8847626f0ff 100644 --- a/drivers/cam_cpas/cam_cpas_soc.c +++ b/drivers/cam_cpas/cam_cpas_soc.c @@ -163,7 +163,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, rc = of_property_read_u32(level_node, "level-index", &level_idx); if (rc) { - CAM_ERR(CAM_CPAS, "Error raeding level idx rc: %d", rc); + CAM_ERR(CAM_CPAS, "Error reading level idx rc: %d", rc); return rc; } if (level_idx >= CAM_CPAS_MAX_TREE_LEVELS) { @@ -229,19 +229,82 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, cpas_core->axi_port[mnoc_idx].axi_port_node = mnoc_node; - rc = of_property_read_string( - curr_node, "qcom,axi-port-name", - &cpas_core->axi_port[mnoc_idx] - .axi_port_name); - if (rc) { - CAM_ERR(CAM_CPAS, - "failed to read mnoc-port-name rc=%d", - rc); - return rc; + if (soc_private->bus_icc_based) { + struct of_phandle_args src_args = {0}, + dst_args = {0}; + + rc = of_property_read_string(mnoc_node, + "interconnect-names", + &cpas_core->axi_port[mnoc_idx] + .bus_client.common_data.name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read interconnect-names rc=%d", + rc); + return rc; + } + + rc = of_parse_phandle_with_args( + mnoc_node, "interconnects", + "#interconnect-cells", 0, + &src_args); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read axi bus src info rc=%d", + rc); + return -EINVAL; + } + + of_node_put(src_args.np); + if (src_args.args_count != 1) { + CAM_ERR(CAM_CPAS, + "Invalid number of axi src args: %d", + src_args.args_count); + return -EINVAL; + } + + cpas_core->axi_port[mnoc_idx].bus_client + .common_data.src_id = src_args.args[0]; + + rc = of_parse_phandle_with_args( + mnoc_node, "interconnects", + "#interconnect-cells", 1, + &dst_args); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read axi bus dst info rc=%d", + rc); + return -EINVAL; + } + + of_node_put(dst_args.np); + if (dst_args.args_count != 1) { + CAM_ERR(CAM_CPAS, + "Invalid number of axi dst args: %d", + dst_args.args_count); + return -EINVAL; + } + + cpas_core->axi_port[mnoc_idx].bus_client + .common_data.dst_id = dst_args.args[0]; + cpas_core->axi_port[mnoc_idx].bus_client + .common_data.num_usecases = 2; + } else { + rc = of_property_read_string( + curr_node, "qcom,axi-port-name", + &cpas_core->axi_port[mnoc_idx] + .bus_client.common_data.name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read mnoc-port-name rc=%d", + rc); + return rc; + } } + cpas_core->axi_port [mnoc_idx].ib_bw_voting_needed - = of_property_read_bool(curr_node, + = of_property_read_bool(curr_node, "ib-bw-voting-needed"); curr_node_ptr->axi_port_idx = mnoc_idx; mnoc_idx++; @@ -392,7 +455,8 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, struct platform_device *pdev, struct cam_cpas_private_soc *soc_private) { struct device_node *of_node; - int count = 0, i = 0, rc = 0; + struct of_phandle_args src_args = {0}, dst_args = {0}; + int count = 0, i = 0, rc = 0, num_bw_values = 0, num_levels = 0; struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; if (!soc_private || !pdev) { @@ -437,6 +501,116 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, soc_private->client_id_based = of_property_read_bool(of_node, "client-id-based"); + soc_private->bus_icc_based = of_property_read_bool(of_node, + "interconnects"); + + if (soc_private->bus_icc_based) { + rc = of_property_read_string(of_node, "interconnect-names", + &cpas_core->ahb_bus_client.common_data.name); + if (rc) { + CAM_ERR(CAM_CPAS, + "device %s failed to read interconnect-names", + pdev->name); + return rc; + } + + rc = of_parse_phandle_with_args(of_node, "interconnects", + "#interconnect-cells", 0, &src_args); + if (rc) { + CAM_ERR(CAM_CPAS, + "device %s failed to read ahb bus src info", + pdev->name); + return rc; + } + + of_node_put(src_args.np); + if (src_args.args_count != 1) { + CAM_ERR(CAM_CPAS, + "Invalid number of ahb src args: %d", + src_args.args_count); + return -EINVAL; + } + + cpas_core->ahb_bus_client.common_data.src_id = src_args.args[0]; + + rc = of_parse_phandle_with_args(of_node, "interconnects", + "#interconnect-cells", 1, &dst_args); + if (rc) { + CAM_ERR(CAM_CPAS, + "device %s failed to read ahb bus dst info", + pdev->name); + return rc; + } + + of_node_put(dst_args.np); + if (dst_args.args_count != 1) { + CAM_ERR(CAM_CPAS, + "Invalid number of ahb dst args: %d", + dst_args.args_count); + return -EINVAL; + } + + cpas_core->ahb_bus_client.common_data.dst_id = dst_args.args[0]; + + rc = of_property_read_u32(of_node, "cam-ahb-num-cases", + &cpas_core->ahb_bus_client.common_data.num_usecases); + if (rc) { + CAM_ERR(CAM_CPAS, + "device %s failed to read ahb num usecases", + pdev->name); + return rc; + } + + if (cpas_core->ahb_bus_client.common_data.num_usecases > + CAM_SOC_BUS_MAX_NUM_USECASES) { + CAM_ERR(CAM_UTIL, "Invalid number of usecases: %d", + cpas_core->ahb_bus_client.common_data + .num_usecases); + return -EINVAL; + } + + num_bw_values = of_property_count_u64_elems(of_node, + "cam-ahb-bw-KBps"); + if (num_bw_values <= 0) { + CAM_ERR(CAM_UTIL, "Error counting ahb bw values"); + return -EINVAL; + } + + num_levels = (num_bw_values / 2); + + if (num_levels != + cpas_core->ahb_bus_client.common_data.num_usecases) { + CAM_ERR(CAM_UTIL, "Invalid number of levels: %d", + num_bw_values/2); + return -EINVAL; + } + + for (i = 0; i < num_levels; i++) { + rc = of_property_read_u64_index(of_node, + "cam-ahb-bw-KBps", + (i * 2), + &cpas_core->ahb_bus_client.common_data + .bw_pair[i].ab); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading ab bw value, rc=%d", + rc); + return rc; + } + + rc = of_property_read_u64_index(of_node, + "cam-ahb-bw-KBps", + ((i * 2) + 1), + &cpas_core->ahb_bus_client.common_data + .bw_pair[i].ib); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading ib bw value, rc=%d", + rc); + return rc; + } + } + } count = of_property_count_strings(of_node, "client-names"); if (count <= 0) { diff --git a/drivers/cam_cpas/cam_cpas_soc.h b/drivers/cam_cpas/cam_cpas_soc.h index fea9c3c97593..ef5eb32337e6 100644 --- a/drivers/cam_cpas/cam_cpas_soc.h +++ b/drivers/cam_cpas/cam_cpas_soc.h @@ -74,6 +74,7 @@ struct cam_cpas_tree_node { * * @arch_compat: ARCH compatible string * @client_id_based: Whether clients are id based + * @bus_icc_based: Interconnect based bus interaction * @num_clients: Number of clients supported * @client_name: Client names * @tree_node: Array of pointers to all tree nodes required to calculate @@ -93,6 +94,7 @@ struct cam_cpas_tree_node { struct cam_cpas_private_soc { const char *arch_compat; bool client_id_based; + bool bus_icc_based; uint32_t num_clients; const char *client_name[CAM_CPAS_MAX_CLIENTS]; struct cam_cpas_tree_node *tree_node[CAM_CPAS_MAX_TREE_NODES]; diff --git a/drivers/cam_utils/cam_soc_bus.c b/drivers/cam_utils/cam_soc_bus.c new file mode 100644 index 000000000000..1cef2610b805 --- /dev/null +++ b/drivers/cam_utils/cam_soc_bus.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_soc_bus.h" + +/** + * struct cam_soc_bus_client_data : Bus client data + * + * @pdata: Bus pdata information + * @client_id: Bus client id + * @num_paths: Number of paths for this client + * @curr_vote_level: current voted index + * @dyn_vote: whether dynamic voting enabled + */ +struct cam_soc_bus_client_data { + struct msm_bus_scale_pdata *pdata; + uint32_t client_id; + int num_paths; + unsigned int curr_vote_level; + bool dyn_vote; +}; + +int cam_soc_bus_client_update_request(void *client, unsigned int idx) +{ + int rc = 0; + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) client; + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + + if (bus_client_data->dyn_vote) { + CAM_ERR(CAM_UTIL, + "Dyn update not allowed client[%d][%s], dyn_vote: %d", + bus_client_data->client_id, + bus_client->common_data->name, + bus_client_data->dyn_vote); + rc = -EINVAL; + goto end; + } + + if (idx >= bus_client->common_data->num_usecases) { + CAM_ERR(CAM_UTIL, "Invalid vote level=%d, usecases=%d", idx, + bus_client->common_data->num_usecases); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_UTIL, "Bus client=[%d][%s] index[%d]", + bus_client_data->client_id, bus_client->common_data->name, idx); + + rc = msm_bus_scale_client_update_request(bus_client_data->client_id, + idx); + if (rc) { + CAM_ERR(CAM_UTIL, + "Update request failed, client[%d][%s], idx: %d", + bus_client_data->client_id, + bus_client->common_data->name, idx); + goto end; + } + +end: + return rc; +} + +int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib) +{ + int idx = 0; + struct msm_bus_paths *path; + struct msm_bus_scale_pdata *pdata; + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) client; + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + int rc = 0; + + if ((bus_client->common_data->num_usecases != 2) || + (bus_client_data->num_paths != 1) || + (!bus_client_data->dyn_vote)) { + CAM_ERR(CAM_UTIL, + "dynamic update not allowed Bus client=[%d][%s], %d %d %d", + bus_client_data->client_id, + bus_client->common_data->name, + bus_client->common_data->num_usecases, + bus_client_data->num_paths, + bus_client_data->dyn_vote); + rc = -EINVAL; + goto end; + } + + idx = bus_client_data->curr_vote_level; + idx = 1 - idx; + bus_client_data->curr_vote_level = idx; + + pdata = bus_client_data->pdata; + path = &(pdata->usecase[idx]); + path->vectors[0].ab = ab; + path->vectors[0].ib = ib; + + CAM_DBG(CAM_UTIL, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", + bus_client_data->client_id, bus_client->common_data->name, ab, + ib, idx); + rc = msm_bus_scale_client_update_request(bus_client_data->client_id, + idx); + if (rc) { + CAM_ERR(CAM_UTIL, + "Update request failed, client[%d][%s], idx: %d", + bus_client_data->client_id, + bus_client->common_data->name, idx); + return rc; + } + +end: + return rc; +} + +int cam_soc_bus_client_register(struct platform_device *pdev, + struct device_node *dev_node, void **client, + struct cam_soc_bus_client_common_data *common_data) +{ + struct msm_bus_scale_pdata *pdata = NULL; + struct cam_soc_bus_client *bus_client = NULL; + struct cam_soc_bus_client_data *bus_client_data = NULL; + uint32_t client_id; + int rc; + + bus_client = kzalloc(sizeof(struct cam_soc_bus_client), GFP_KERNEL); + if (!bus_client) { + CAM_ERR(CAM_UTIL, "Non Enought Memroy"); + rc = -ENOMEM; + goto end; + } + + *client = bus_client; + + bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data), + GFP_KERNEL); + if (!bus_client_data) { + kfree(bus_client); + *client = NULL; + rc = -ENOMEM; + goto end; + } + + bus_client->client_data = bus_client_data; + pdata = msm_bus_pdata_from_node(pdev, + dev_node); + if (!pdata) { + CAM_ERR(CAM_UTIL, "failed get_pdata"); + rc = -EINVAL; + goto error; + } + + if ((pdata->num_usecases == 0) || + (pdata->usecase[0].num_paths == 0)) { + CAM_ERR(CAM_UTIL, "usecase=%d", pdata->num_usecases); + rc = -EINVAL; + goto error; + } + + client_id = msm_bus_scale_register_client(pdata); + if (!client_id) { + CAM_ERR(CAM_UTIL, "failed in register bus client_data"); + rc = -EINVAL; + goto error; + } + + bus_client->common_data = common_data; + + bus_client_data->dyn_vote = of_property_read_bool(dev_node, + "qcom,msm-bus-vector-dyn-vote"); + + if (bus_client_data->dyn_vote && (pdata->num_usecases != 2)) { + CAM_ERR(CAM_UTIL, "Excess or less vectors %d", + pdata->num_usecases); + rc = -EINVAL; + goto fail_unregister_client; + } + + rc = msm_bus_scale_client_update_request(client_id, 0); + if (rc) { + CAM_ERR(CAM_UTIL, "Bus client update request failed, rc = %d", + rc); + goto fail_unregister_client; + } + + bus_client->common_data->src_id = pdata->usecase[0].vectors[0].src; + bus_client->common_data->dst_id = pdata->usecase[0].vectors[0].dst; + bus_client_data->pdata = pdata; + bus_client_data->client_id = client_id; + bus_client->common_data->num_usecases = pdata->num_usecases; + bus_client_data->num_paths = pdata->usecase[0].num_paths; + bus_client->common_data->name = pdata->name; + + CAM_DBG(CAM_UTIL, "Bus Client=[%d][%s] : src=%d, dst=%d", + bus_client_data->client_id, bus_client->common_data->name, + bus_client->common_data->src_id, + bus_client->common_data->dst_id); + + return 0; +fail_unregister_client: + msm_bus_scale_unregister_client(bus_client_data->client_id); +error: + kfree(bus_client_data); + bus_client->client_data = NULL; + kfree(bus_client); + *client = NULL; +end: + return rc; + +} + +void cam_soc_bus_client_unregister(void **client) +{ + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) (*client); + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + + if (bus_client_data->dyn_vote) + cam_soc_bus_client_update_bw(bus_client, 0, 0); + else + cam_soc_bus_client_update_request(bus_client, 0); + + msm_bus_scale_unregister_client(bus_client_data->client_id); + kfree(bus_client_data); + bus_client->client_data = NULL; + kfree(bus_client); + *client = NULL; +} diff --git a/drivers/cam_utils/cam_soc_bus.h b/drivers/cam_utils/cam_soc_bus.h new file mode 100644 index 000000000000..518b6524d038 --- /dev/null +++ b/drivers/cam_utils/cam_soc_bus.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SOC_BUS_H_ +#define _CAM_SOC_BUS_H_ + +#include +#include +#include +#include "cam_debug_util.h" + +#define CAM_SOC_BUS_MAX_NUM_USECASES 8 + +/** + * struct cam_soc_bus_client_ab_ib : Bandwidth values for selected usecase + * + * @ab: Arbitrated Bandwidth + * @ib: Instantaneous Bandwidth + */ +struct cam_soc_bus_client_ab_ib { + uint64_t ab; + uint64_t ib; +}; + +/** + * struct cam_soc_bus_client_common_data : Common data fields for bus client + * + * @name: Name of bus client + * @src_id: Bus master/src id + * @dst_id: Bus slave/dst id + * @num_usecases: Number of use cases for this client + * @bw_pair: Bandwidth values for applicable usecases + */ +struct cam_soc_bus_client_common_data { + const char *name; + uint32_t src_id; + uint32_t dst_id; + int num_usecases; + struct cam_soc_bus_client_ab_ib bw_pair[CAM_SOC_BUS_MAX_NUM_USECASES]; +}; + +/** + * struct cam_soc_bus_client : Bus client information + * + * @client_data: Bus client data + * @common_data: Common data fields for bus client + */ +struct cam_soc_bus_client { + void *client_data; + struct cam_soc_bus_client_common_data *common_data; +}; + + +#if IS_REACHABLE(CONFIG_QCOM_BUS_SCALING) || \ + IS_REACHABLE(CONFIG_INTERCONNECT_QCOM) + +int cam_soc_bus_client_update_request(void *client, unsigned int idx); + +int cam_soc_bus_client_update_bw(void *client, uint64_t ab, + uint64_t ib); + +int cam_soc_bus_client_register(struct platform_device *pdev, + struct device_node *dev_node, void **client, + struct cam_soc_bus_client_common_data *common_data); + +void cam_soc_bus_client_unregister(void **client); + +#else +static inline int cam_soc_bus_client_update_request(void *client, + unsigned int idx) +{ + return 0; +} + +static inline int cam_soc_bus_client_update_bw(void *client, + uint64_t ab, uint64_t ib) +{ + return 0; +} + +static inline int cam_soc_bus_client_register( + struct platform_device *pdev, struct device_node *dev_node, + void **client, struct cam_soc_bus_client_common_data *common_data) +{ + return 0; +} + +static inline void cam_soc_bus_client_unregister(void **client) +{ +} + +#endif + +#endif /* _CAM_SOC_BUS_H_ */ diff --git a/drivers/cam_utils/cam_soc_icc.c b/drivers/cam_utils/cam_soc_icc.c new file mode 100644 index 000000000000..0a22cecc3c08 --- /dev/null +++ b/drivers/cam_utils/cam_soc_icc.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include +#include "cam_soc_bus.h" + +/** + * struct cam_soc_bus_client_data : Bus client data + * + * @icc_data: Bus icc path information + */ +struct cam_soc_bus_client_data { + struct icc_path *icc_data; +}; + +int cam_soc_bus_client_update_request(void *client, unsigned int idx) +{ + int rc = 0; + uint64_t ab = 0, ib = 0; + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) client; + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + + if (idx >= bus_client->common_data->num_usecases) { + CAM_ERR(CAM_UTIL, "Invalid vote level=%d, usecases=%d", idx, + bus_client->common_data->num_usecases); + rc = -EINVAL; + goto end; + } + + ab = bus_client->common_data->bw_pair[idx].ab; + ib = bus_client->common_data->bw_pair[idx].ib; + + CAM_DBG(CAM_UTIL, "Bus client=[%s] index[%d]", + bus_client->common_data->name, idx); + + rc = icc_set_bw(bus_client_data->icc_data, ab, ib); + if (rc) { + CAM_ERR(CAM_UTIL, + "Update request failed, client[%s], idx: %d", + bus_client->common_data->name, idx); + goto end; + } + +end: + return rc; +} + +int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib) +{ + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) client; + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + int rc = 0; + + CAM_DBG(CAM_UTIL, "Bus client=[%s] :ab[%llu] ib[%llu]", + bus_client->common_data->name, ab, ib); + rc = icc_set_bw(bus_client_data->icc_data, ab, ib); + if (rc) { + CAM_ERR(CAM_UTIL, "Update request failed, client[%s]", + bus_client->common_data->name); + goto end; + } + +end: + return rc; +} + +int cam_soc_bus_client_register(struct platform_device *pdev, + struct device_node *dev_node, void **client, + struct cam_soc_bus_client_common_data *common_data) +{ + struct cam_soc_bus_client *bus_client = NULL; + struct cam_soc_bus_client_data *bus_client_data = NULL; + int rc = 0; + + bus_client = kzalloc(sizeof(struct cam_soc_bus_client), GFP_KERNEL); + if (!bus_client) { + CAM_ERR(CAM_UTIL, "soc bus client is NULL"); + rc = -ENOMEM; + goto end; + } + + *client = bus_client; + + bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data), + GFP_KERNEL); + if (!bus_client_data) { + kfree(bus_client); + *client = NULL; + rc = -ENOMEM; + goto end; + } + + bus_client->client_data = bus_client_data; + bus_client_data->icc_data = icc_get(&pdev->dev, + bus_client->common_data->src_id, + bus_client->common_data->dst_id); + if (!bus_client_data->icc_data) { + CAM_ERR(CAM_UTIL, "failed in register bus client"); + rc = -EINVAL; + goto error; + } + + bus_client->common_data = common_data; + + rc = icc_set_bw(bus_client_data->icc_data, 0, 0); + if (rc) { + CAM_ERR(CAM_UTIL, "Bus client update request failed, rc = %d", + rc); + goto fail_unregister_client; + } + + CAM_DBG(CAM_UTIL, "Bus Client=[%s] : src=%d, dst=%d", + bus_client->common_data->name, bus_client->common_data->src_id, + bus_client->common_data->dst_id); + + return 0; + +fail_unregister_client: + icc_put(bus_client_data->icc_data); +error: + kfree(bus_client_data); + bus_client->client_data = NULL; + kfree(bus_client); + *client = NULL; +end: + return rc; + +} + +void cam_soc_bus_client_unregister(void **client) +{ + struct cam_soc_bus_client *bus_client = + (struct cam_soc_bus_client *) (*client); + struct cam_soc_bus_client_data *bus_client_data = + (struct cam_soc_bus_client_data *) bus_client->client_data; + + icc_put(bus_client_data->icc_data); + kfree(bus_client_data); + bus_client->client_data = NULL; + kfree(bus_client); + *client = NULL; + +}