mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 13:49:24 -04:00
Merge "msm: camera: cpas: Add support for camnoc based voting" into camera-kernel.lnx.4.0
This commit is contained in:
commit
8564b8d28b
4 changed files with 208 additions and 28 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue