Loading drivers/cam_cpas/cam_cpas_hw.c +141 −23 Original line number Diff line number Diff line Loading @@ -242,6 +242,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, return -EINVAL; } if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", cpas_core->num_camnoc_axi_ports); return -EINVAL; } for (i = 0; i < cpas_core->num_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->axi_port[i].bus_client); Loading @@ -249,6 +255,13 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, cpas_core->axi_port[i].axi_port_node = NULL; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->camnoc_axi_port[i].bus_client); of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node); cpas_core->camnoc_axi_port[i].axi_port_node = NULL; } return 0; } Loading @@ -257,6 +270,7 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, { int i = 0, rc = 0; struct device_node *axi_port_mnoc_node = NULL; struct device_node *axi_port_camnoc_node = NULL; if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", Loading @@ -271,6 +285,15 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, if (rc) goto bus_register_fail; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { axi_port_camnoc_node = cpas_core->camnoc_axi_port[i].axi_port_node; rc = cam_cpas_util_register_bus_client(soc_info, axi_port_camnoc_node, &cpas_core->camnoc_axi_port[i].bus_client); if (rc) goto bus_register_fail; } return 0; bus_register_fail: Loading Loading @@ -608,6 +631,99 @@ static int cam_cpas_axi_consolidate_path_votes( return rc; } static int cam_cpas_update_axi_vote_bw( struct cam_hw_info *cpas_hw, struct cam_cpas_tree_node *cpas_tree_node, bool *mnoc_axi_port_updated, bool *camnoc_axi_port_updated) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", cpas_tree_node->axi_port_idx); return -EINVAL; } cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw = cpas_tree_node->mnoc_ab_bw; cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw = cpas_tree_node->mnoc_ib_bw; mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true; if (soc_private->control_camnoc_axi_clk) return 0; cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = cpas_tree_node->camnoc_bw; camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; return 0; } static int cam_cpas_camnoc_set_vote_axi_clk_rate( struct cam_hw_info *cpas_hw, bool *camnoc_axi_port_updated) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; int i; int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); return rc; } /* Below code is executed if we just vote and do not set the clk rate * for camnoc */ if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", cpas_core->num_camnoc_axi_ports); return -EINVAL; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { if (camnoc_axi_port_updated[i]) camnoc_axi_port = &cpas_core->camnoc_axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", camnoc_axi_port->axi_port_name, camnoc_axi_port->camnoc_bw); if (camnoc_axi_port->camnoc_bw) camnoc_bw = camnoc_axi_port->camnoc_bw; else camnoc_bw = camnoc_axi_port->additional_bw; rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, 0, camnoc_bw, true); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", camnoc_bw, rc, camnoc_axi_port->axi_port_name); if (rc) { CAM_ERR(CAM_CPAS, "Failed in camnoc vote camnoc_bw[%llu] rc=%d", camnoc_bw, rc); break; } } return rc; } static int cam_cpas_util_apply_client_axi_vote( struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, Loading @@ -615,12 +731,13 @@ static int cam_cpas_util_apply_client_axi_vote( { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_axi_vote *con_axi_vote = NULL; struct cam_cpas_axi_port *axi_port = NULL; struct cam_cpas_axi_port *mnoc_axi_port = NULL; struct cam_cpas_tree_node *curr_tree_node = NULL; struct cam_cpas_tree_node *par_tree_node = NULL; uint32_t transac_type; uint32_t path_data_type; bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; Loading @@ -643,7 +760,7 @@ static int cam_cpas_util_apply_client_axi_vote( cpas_core->axi_port[i].additional_bw -= CAM_CPAS_DEFAULT_AXI_BW; } axi_port_updated[i] = true; mnoc_axi_port_updated[i] = true; } goto vote_start_clients; } Loading Loading @@ -733,15 +850,15 @@ static int cam_cpas_util_apply_client_axi_vote( rc = -EINVAL; goto unlock_tree; } cpas_core->axi_port [par_tree_node->axi_port_idx].ab_bw = par_tree_node->mnoc_ab_bw; cpas_core->axi_port [par_tree_node->axi_port_idx].ib_bw = par_tree_node->mnoc_ib_bw; axi_port_updated[par_tree_node->axi_port_idx] = true; rc = cam_cpas_update_axi_vote_bw(cpas_hw, par_tree_node, mnoc_axi_port_updated, camnoc_axi_port_updated); if (rc) { CAM_ERR(CAM_CPAS, "Update Vote failed"); goto unlock_tree; } } curr_tree_node = par_tree_node; Loading @@ -759,26 +876,27 @@ static int cam_cpas_util_apply_client_axi_vote( vote_start_clients: for (i = 0; i < cpas_core->num_axi_ports; i++) { if (axi_port_updated[i]) axi_port = &cpas_core->axi_port[i]; if (mnoc_axi_port_updated[i]) mnoc_axi_port = &cpas_core->axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", axi_port->axi_port_name, axi_port->ab_bw, axi_port->ib_bw, axi_port->additional_bw); mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw); if (axi_port->ab_bw) mnoc_ab_bw = axi_port->ab_bw; if (mnoc_axi_port->ab_bw) mnoc_ab_bw = mnoc_axi_port->ab_bw; else mnoc_ab_bw = axi_port->additional_bw; mnoc_ab_bw = mnoc_axi_port->additional_bw; if (cpas_core->axi_port[i].ib_bw_voting_needed) mnoc_ib_bw = axi_port->ib_bw; mnoc_ib_bw = mnoc_axi_port->ib_bw; else mnoc_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, mnoc_ab_bw, mnoc_ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, Loading @@ -787,8 +905,8 @@ static int cam_cpas_util_apply_client_axi_vote( goto unlock_tree; } } rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); Loading drivers/cam_cpas/cam_cpas_hw.h +7 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_HW_H_ Loading Loading @@ -153,6 +153,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing AXI Port info in device tree * @ab_bw: AB bw value for this port * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients */ struct cam_cpas_axi_port { Loading @@ -162,6 +163,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; uint64_t ab_bw; uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; }; Loading @@ -174,11 +176,13 @@ struct cam_cpas_axi_port { * @tree_lock: Mutex lock for accessing CPAS node tree * @num_clients: Total number of clients that CPAS supports * @num_axi_ports: Total number of axi ports found in device tree * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree * @registered_clients: Number of Clients registered currently * @streamon_clients: Number of Clients that are in start state currently * @regbase_index: Register base indices for CPAS register base IDs * @ahb_bus_client: AHB Bus client info * @axi_port: AXI port info for a specific axi index * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index * @internal_ops: CPAS HW internal ops * @work_queue: Work queue handle * @irq_count: atomic irq count Loading @@ -193,11 +197,13 @@ struct cam_cpas { struct mutex tree_lock; uint32_t num_clients; uint32_t num_axi_ports; uint32_t num_camnoc_axi_ports; uint32_t registered_clients; uint32_t streamon_clients; int32_t regbase_index[CAM_CPAS_REG_MAX]; struct cam_cpas_bus_client ahb_bus_client; struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_internal_ops internal_ops; struct workqueue_struct *work_queue; atomic_t irq_count; Loading drivers/cam_cpas/cam_cpas_soc.c +53 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,47 @@ static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) return 0; } static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core, struct device_node *curr_node, struct cam_cpas_tree_node *cpas_node_ptr, int *camnoc_idx) { struct device_node *camnoc_node; int rc; camnoc_node = of_find_node_by_name(curr_node, "qcom,axi-port-camnoc"); if (camnoc_node) { if (*camnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d", *camnoc_idx); return -EINVAL; } cpas_core->camnoc_axi_port[*camnoc_idx] .axi_port_node = camnoc_node; rc = of_property_read_string( curr_node, "qcom,axi-port-name", &cpas_core->camnoc_axi_port[*camnoc_idx] .axi_port_name); if (rc) { CAM_ERR(CAM_CPAS, "fail to read camnoc-port-name rc=%d", rc); return rc; } cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx; cpas_core->num_camnoc_axi_ports++; (*camnoc_idx)++; } return 0; } static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *of_node, struct cam_cpas_private_soc *soc_private) { Loading @@ -142,7 +183,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *curr_node; struct device_node *parent_node; struct device_node *mnoc_node; int mnoc_idx = 0; int mnoc_idx = 0, camnoc_idx = 0; uint32_t path_idx; bool camnoc_max_needed = false; struct cam_cpas_tree_node *curr_node_ptr = NULL; Loading Loading @@ -248,6 +289,17 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, cpas_core->num_axi_ports++; } if (!soc_private->control_camnoc_axi_clk) { rc = cam_cpas_update_camnoc_node( cpas_core, curr_node, curr_node_ptr, &camnoc_idx); if (rc) { CAM_ERR(CAM_CPAS, "Parse Camnoc port fail"); return rc; } } rc = of_property_read_string(curr_node, "client-name", &client_name); if (!rc) { Loading drivers/cam_cpas/cam_cpas_soc.h +2 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ struct cam_cpas_vdd_ahb_mapping { * @cell_idx: Index to identify node from device tree and its parent * @level_idx: Index to identify at what level the node is present * @axi_port_idx: Index to identify which axi port to vote the consolidated bw * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) * @path_trans_type: Transaction type info from device tree (rd, wr) * @merge_type: Traffic merge type (calculation info) from device tree Loading @@ -54,6 +55,7 @@ struct cam_cpas_tree_node { uint32_t cell_idx; uint32_t level_idx; int axi_port_idx; int camnoc_axi_port_idx; const char *node_name; uint32_t path_data_type; uint32_t path_trans_type; Loading Loading
drivers/cam_cpas/cam_cpas_hw.c +141 −23 Original line number Diff line number Diff line Loading @@ -242,6 +242,12 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, return -EINVAL; } if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", cpas_core->num_camnoc_axi_ports); return -EINVAL; } for (i = 0; i < cpas_core->num_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->axi_port[i].bus_client); Loading @@ -249,6 +255,13 @@ static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, cpas_core->axi_port[i].axi_port_node = NULL; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { cam_cpas_util_unregister_bus_client( &cpas_core->camnoc_axi_port[i].bus_client); of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node); cpas_core->camnoc_axi_port[i].axi_port_node = NULL; } return 0; } Loading @@ -257,6 +270,7 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, { int i = 0, rc = 0; struct device_node *axi_port_mnoc_node = NULL; struct device_node *axi_port_camnoc_node = NULL; if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", Loading @@ -271,6 +285,15 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, if (rc) goto bus_register_fail; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { axi_port_camnoc_node = cpas_core->camnoc_axi_port[i].axi_port_node; rc = cam_cpas_util_register_bus_client(soc_info, axi_port_camnoc_node, &cpas_core->camnoc_axi_port[i].bus_client); if (rc) goto bus_register_fail; } return 0; bus_register_fail: Loading Loading @@ -608,6 +631,99 @@ static int cam_cpas_axi_consolidate_path_votes( return rc; } static int cam_cpas_update_axi_vote_bw( struct cam_hw_info *cpas_hw, struct cam_cpas_tree_node *cpas_tree_node, bool *mnoc_axi_port_updated, bool *camnoc_axi_port_updated) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", cpas_tree_node->axi_port_idx); return -EINVAL; } cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw = cpas_tree_node->mnoc_ab_bw; cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw = cpas_tree_node->mnoc_ib_bw; mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true; if (soc_private->control_camnoc_axi_clk) return 0; cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = cpas_tree_node->camnoc_bw; camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; return 0; } static int cam_cpas_camnoc_set_vote_axi_clk_rate( struct cam_hw_info *cpas_hw, bool *camnoc_axi_port_updated) { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_cpas_private_soc *soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; int i; int rc = 0; struct cam_cpas_axi_port *camnoc_axi_port = NULL; uint64_t camnoc_bw; if (soc_private->control_camnoc_axi_clk) { rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); return rc; } /* Below code is executed if we just vote and do not set the clk rate * for camnoc */ if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", cpas_core->num_camnoc_axi_ports); return -EINVAL; } for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { if (camnoc_axi_port_updated[i]) camnoc_axi_port = &cpas_core->camnoc_axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", camnoc_axi_port->axi_port_name, camnoc_axi_port->camnoc_bw); if (camnoc_axi_port->camnoc_bw) camnoc_bw = camnoc_axi_port->camnoc_bw; else camnoc_bw = camnoc_axi_port->additional_bw; rc = cam_cpas_util_vote_bus_client_bw( &camnoc_axi_port->bus_client, 0, camnoc_bw, true); CAM_DBG(CAM_CPAS, "camnoc vote camnoc_bw[%llu] rc=%d %s", camnoc_bw, rc, camnoc_axi_port->axi_port_name); if (rc) { CAM_ERR(CAM_CPAS, "Failed in camnoc vote camnoc_bw[%llu] rc=%d", camnoc_bw, rc); break; } } return rc; } static int cam_cpas_util_apply_client_axi_vote( struct cam_hw_info *cpas_hw, struct cam_cpas_client *cpas_client, Loading @@ -615,12 +731,13 @@ static int cam_cpas_util_apply_client_axi_vote( { struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; struct cam_axi_vote *con_axi_vote = NULL; struct cam_cpas_axi_port *axi_port = NULL; struct cam_cpas_axi_port *mnoc_axi_port = NULL; struct cam_cpas_tree_node *curr_tree_node = NULL; struct cam_cpas_tree_node *par_tree_node = NULL; uint32_t transac_type; uint32_t path_data_type; bool axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; Loading @@ -643,7 +760,7 @@ static int cam_cpas_util_apply_client_axi_vote( cpas_core->axi_port[i].additional_bw -= CAM_CPAS_DEFAULT_AXI_BW; } axi_port_updated[i] = true; mnoc_axi_port_updated[i] = true; } goto vote_start_clients; } Loading Loading @@ -733,15 +850,15 @@ static int cam_cpas_util_apply_client_axi_vote( rc = -EINVAL; goto unlock_tree; } cpas_core->axi_port [par_tree_node->axi_port_idx].ab_bw = par_tree_node->mnoc_ab_bw; cpas_core->axi_port [par_tree_node->axi_port_idx].ib_bw = par_tree_node->mnoc_ib_bw; axi_port_updated[par_tree_node->axi_port_idx] = true; rc = cam_cpas_update_axi_vote_bw(cpas_hw, par_tree_node, mnoc_axi_port_updated, camnoc_axi_port_updated); if (rc) { CAM_ERR(CAM_CPAS, "Update Vote failed"); goto unlock_tree; } } curr_tree_node = par_tree_node; Loading @@ -759,26 +876,27 @@ static int cam_cpas_util_apply_client_axi_vote( vote_start_clients: for (i = 0; i < cpas_core->num_axi_ports; i++) { if (axi_port_updated[i]) axi_port = &cpas_core->axi_port[i]; if (mnoc_axi_port_updated[i]) mnoc_axi_port = &cpas_core->axi_port[i]; else continue; CAM_DBG(CAM_PERF, "Port[%s] : ab=%lld ib=%lld additional=%lld", axi_port->axi_port_name, axi_port->ab_bw, axi_port->ib_bw, axi_port->additional_bw); mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw); if (axi_port->ab_bw) mnoc_ab_bw = axi_port->ab_bw; if (mnoc_axi_port->ab_bw) mnoc_ab_bw = mnoc_axi_port->ab_bw; else mnoc_ab_bw = axi_port->additional_bw; mnoc_ab_bw = mnoc_axi_port->additional_bw; if (cpas_core->axi_port[i].ib_bw_voting_needed) mnoc_ib_bw = axi_port->ib_bw; mnoc_ib_bw = mnoc_axi_port->ib_bw; else mnoc_ib_bw = 0; rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, rc = cam_cpas_util_vote_bus_client_bw( &mnoc_axi_port->bus_client, mnoc_ab_bw, mnoc_ib_bw, false); if (rc) { CAM_ERR(CAM_CPAS, Loading @@ -787,8 +905,8 @@ static int cam_cpas_util_apply_client_axi_vote( goto unlock_tree; } } rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); rc = cam_cpas_camnoc_set_vote_axi_clk_rate( cpas_hw, camnoc_axi_port_updated); if (rc) CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); Loading
drivers/cam_cpas/cam_cpas_hw.h +7 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CPAS_HW_H_ Loading Loading @@ -153,6 +153,7 @@ struct cam_cpas_bus_client { * @axi_port_node: Node representing AXI Port info in device tree * @ab_bw: AB bw value for this port * @ib_bw: IB bw value for this port * @camnoc_bw: CAMNOC bw value for this port * @additional_bw: Additional bandwidth to cover non-hw cpas clients */ struct cam_cpas_axi_port { Loading @@ -162,6 +163,7 @@ struct cam_cpas_axi_port { struct device_node *axi_port_node; uint64_t ab_bw; uint64_t ib_bw; uint64_t camnoc_bw; uint64_t additional_bw; }; Loading @@ -174,11 +176,13 @@ struct cam_cpas_axi_port { * @tree_lock: Mutex lock for accessing CPAS node tree * @num_clients: Total number of clients that CPAS supports * @num_axi_ports: Total number of axi ports found in device tree * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree * @registered_clients: Number of Clients registered currently * @streamon_clients: Number of Clients that are in start state currently * @regbase_index: Register base indices for CPAS register base IDs * @ahb_bus_client: AHB Bus client info * @axi_port: AXI port info for a specific axi index * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index * @internal_ops: CPAS HW internal ops * @work_queue: Work queue handle * @irq_count: atomic irq count Loading @@ -193,11 +197,13 @@ struct cam_cpas { struct mutex tree_lock; uint32_t num_clients; uint32_t num_axi_ports; uint32_t num_camnoc_axi_ports; uint32_t registered_clients; uint32_t streamon_clients; int32_t regbase_index[CAM_CPAS_REG_MAX]; struct cam_cpas_bus_client ahb_bus_client; struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS]; struct cam_cpas_internal_ops internal_ops; struct workqueue_struct *work_queue; atomic_t irq_count; Loading
drivers/cam_cpas/cam_cpas_soc.c +53 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,47 @@ static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) return 0; } static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core, struct device_node *curr_node, struct cam_cpas_tree_node *cpas_node_ptr, int *camnoc_idx) { struct device_node *camnoc_node; int rc; camnoc_node = of_find_node_by_name(curr_node, "qcom,axi-port-camnoc"); if (camnoc_node) { if (*camnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) { CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d", *camnoc_idx); return -EINVAL; } cpas_core->camnoc_axi_port[*camnoc_idx] .axi_port_node = camnoc_node; rc = of_property_read_string( curr_node, "qcom,axi-port-name", &cpas_core->camnoc_axi_port[*camnoc_idx] .axi_port_name); if (rc) { CAM_ERR(CAM_CPAS, "fail to read camnoc-port-name rc=%d", rc); return rc; } cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx; cpas_core->num_camnoc_axi_ports++; (*camnoc_idx)++; } return 0; } static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *of_node, struct cam_cpas_private_soc *soc_private) { Loading @@ -142,7 +183,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, struct device_node *curr_node; struct device_node *parent_node; struct device_node *mnoc_node; int mnoc_idx = 0; int mnoc_idx = 0, camnoc_idx = 0; uint32_t path_idx; bool camnoc_max_needed = false; struct cam_cpas_tree_node *curr_node_ptr = NULL; Loading Loading @@ -248,6 +289,17 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, cpas_core->num_axi_ports++; } if (!soc_private->control_camnoc_axi_clk) { rc = cam_cpas_update_camnoc_node( cpas_core, curr_node, curr_node_ptr, &camnoc_idx); if (rc) { CAM_ERR(CAM_CPAS, "Parse Camnoc port fail"); return rc; } } rc = of_property_read_string(curr_node, "client-name", &client_name); if (!rc) { Loading
drivers/cam_cpas/cam_cpas_soc.h +2 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ struct cam_cpas_vdd_ahb_mapping { * @cell_idx: Index to identify node from device tree and its parent * @level_idx: Index to identify at what level the node is present * @axi_port_idx: Index to identify which axi port to vote the consolidated bw * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) * @path_trans_type: Transaction type info from device tree (rd, wr) * @merge_type: Traffic merge type (calculation info) from device tree Loading @@ -54,6 +55,7 @@ struct cam_cpas_tree_node { uint32_t cell_idx; uint32_t level_idx; int axi_port_idx; int camnoc_axi_port_idx; const char *node_name; uint32_t path_data_type; uint32_t path_trans_type; Loading