Merge "msm: camera: cpas: Add support for camnoc based voting" into camera-kernel.lnx.4.0

This commit is contained in:
Camera Software Integration 2020-02-07 15:12:50 -08:00 • committed by Gerrit - the friendly Code Review server
commit 8564b8d28b
4 changed files with 208 additions and 28 deletions

View file

@ -1,6 +1,6 @@
// 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.
*/
#include <linux/device.h>
@ -177,6 +177,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);
@ -184,6 +190,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;
}
@ -192,6 +205,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",
@ -206,6 +220,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:
@ -543,6 +566,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,
@ -550,12 +666,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;
@ -578,7 +695,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;
}
@ -668,15 +785,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;
@ -694,26 +811,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->bus_client.common_data.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,
@ -722,8 +840,8 @@ vote_start_clients:
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);

View file

@ -1,6 +1,6 @@
/* 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_
@ -136,19 +136,23 @@ struct cam_cpas_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
* @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 {
const char *axi_port_name;
struct cam_cpas_bus_client bus_client;
bool ib_bw_voting_needed;
struct device_node *axi_port_node;
uint64_t ab_bw;
uint64_t ib_bw;
uint64_t camnoc_bw;
uint64_t additional_bw;
};
@ -161,11 +165,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
@ -180,11 +186,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;

View file

@ -1,6 +1,6 @@
// 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.
*/
#include <linux/device.h>
@ -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)
{
@ -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;
@ -311,6 +352,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) {

View file

@ -1,6 +1,6 @@
/* 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_SOC_H_
@ -30,6 +30,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
@ -53,6 +54,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;