msm: camera: common: Add support for DRV config
Add DRV config blob handling for programming required registers per request. Also, add debugfs entry for disabling DRV feature from ife hw manager. Update existing BW voting logs to reflect DRV vote level info. Add support for communicating with rsc device upon update in MNOC BW. Also, update BW voting logic in cpas to accommodate DRV voting to interconnect framework. CRs-Fixed: 3065551 Change-Id: I8ac4820b7af824f5ff46614ae6804001deca9b01 Signed-off-by: Mukund Madhusudan Atre <quic_matre@quicinc.com>
This commit is contained in:

committed by
Camera Software Integration

parent
c73578236c
commit
65878f05bb
@@ -6,6 +6,7 @@ CONFIG_SPECTRA_ICP := y
|
||||
CONFIG_SPECTRA_JPEG := y
|
||||
CONFIG_SPECTRA_CUSTOM := y
|
||||
CONFIG_SPECTRA_SENSOR := y
|
||||
CONFIG_USE_RPMH_DRV_API := n
|
||||
|
||||
# Flags to pass into C preprocessor
|
||||
ccflags-y += -DCONFIG_SPECTRA_ISP=1
|
||||
|
@@ -20,6 +20,9 @@
|
||||
#include "cam_cpastop_hw.h"
|
||||
|
||||
#define CAM_CPAS_LOG_BUF_LEN 512
|
||||
#define CAM_CPAS_APPLY_TYPE_START 1
|
||||
#define CAM_CPAS_APPLY_TYPE_STOP 2
|
||||
#define CAM_CPAS_APPLY_TYPE_UPDATE 3
|
||||
|
||||
static uint cam_min_camnoc_ib_bw;
|
||||
module_param(cam_min_camnoc_ib_bw, uint, 0644);
|
||||
@@ -175,7 +178,60 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_util_vote_bus_client_bw(
|
||||
static int cam_cpas_util_vote_drv_bus_client_bw(struct cam_cpas_bus_client *bus_client,
|
||||
struct cam_cpas_axi_bw_info *curr_vote, struct cam_cpas_axi_bw_info *applied_vote)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!bus_client->valid) {
|
||||
CAM_ERR(CAM_CPAS, "bus client: %s not valid",
|
||||
bus_client->common_data.name);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mutex_lock(&bus_client->lock);
|
||||
if ((curr_vote->drv_vote.high.ab > 0) &&
|
||||
(curr_vote->drv_vote.high.ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW))
|
||||
curr_vote->drv_vote.high.ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW;
|
||||
|
||||
if ((curr_vote->drv_vote.high.ib > 0) &&
|
||||
(curr_vote->drv_vote.high.ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW))
|
||||
curr_vote->drv_vote.high.ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
|
||||
|
||||
CAM_DBG(CAM_CPAS, "Bus_client: %s, DRV vote high=[%llu %llu] low=[%llu %llu]",
|
||||
bus_client->common_data.name, curr_vote->drv_vote.high.ab,
|
||||
curr_vote->drv_vote.high.ib, curr_vote->drv_vote.low.ab,
|
||||
curr_vote->drv_vote.low.ib);
|
||||
|
||||
rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, curr_vote->drv_vote.high.ab,
|
||||
curr_vote->drv_vote.high.ib, CAM_SOC_BUS_PATH_DATA_DRV_HIGH);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Update bw failed, Bus path: %s ab[%llu] ib[%llu]",
|
||||
cam_soc_bus_path_data_to_str(CAM_SOC_BUS_PATH_DATA_DRV_HIGH),
|
||||
curr_vote->drv_vote.high.ab, curr_vote->drv_vote.high.ib);
|
||||
goto unlock_client;
|
||||
}
|
||||
|
||||
rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, curr_vote->drv_vote.low.ab,
|
||||
curr_vote->drv_vote.low.ib, CAM_SOC_BUS_PATH_DATA_DRV_LOW);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Update bw failed, Bus path: %s ab[%llu] ib[%llu]",
|
||||
cam_soc_bus_path_data_to_str(CAM_SOC_BUS_PATH_DATA_DRV_LOW),
|
||||
curr_vote->drv_vote.low.ab, curr_vote->drv_vote.low.ib);
|
||||
goto unlock_client;
|
||||
}
|
||||
|
||||
if (applied_vote)
|
||||
memcpy(applied_vote, curr_vote, sizeof(struct cam_cpas_axi_bw_info));
|
||||
|
||||
unlock_client:
|
||||
mutex_unlock(&bus_client->lock);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_util_vote_hlos_bus_client_bw(
|
||||
struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
|
||||
bool camnoc_bw, uint64_t *applied_ab, uint64_t *applied_ib)
|
||||
{
|
||||
@@ -228,11 +284,12 @@ static int cam_cpas_util_vote_bus_client_bw(
|
||||
cam_cpas_process_bw_overrides(bus_client, &ab, &ib,
|
||||
&cam_debug->cpas_settings);
|
||||
|
||||
rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib);
|
||||
rc = cam_soc_bus_client_update_bw(bus_client->soc_bus_client, ab, ib,
|
||||
CAM_SOC_BUS_PATH_DATA_HLOS);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Update bw failed, ab[%llu] ib[%llu]",
|
||||
ab, ib);
|
||||
"Update bw failed, Bus path %s ab[%llu] ib[%llu]",
|
||||
cam_soc_bus_path_data_to_str(CAM_SOC_BUS_PATH_DATA_HLOS), ab, ib);
|
||||
goto unlock_client;
|
||||
}
|
||||
|
||||
@@ -378,7 +435,10 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw,
|
||||
}
|
||||
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
rc = cam_cpas_util_vote_bus_client_bw(
|
||||
if (cpas_core->axi_port[i].bus_client.common_data.is_drv_port)
|
||||
continue;
|
||||
|
||||
rc = cam_cpas_util_vote_hlos_bus_client_bw(
|
||||
&cpas_core->axi_port[i].bus_client,
|
||||
ab_bw, ib_bw, false, &applied_ab_bw, &applied_ib_bw);
|
||||
if (rc) {
|
||||
@@ -387,8 +447,9 @@ static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw,
|
||||
enable, rc);
|
||||
goto remove_ahb_vote;
|
||||
}
|
||||
cpas_core->axi_port[i].applied_ab_bw = applied_ab_bw;
|
||||
cpas_core->axi_port[i].applied_ib_bw = applied_ib_bw;
|
||||
|
||||
cpas_core->axi_port[i].applied_bw.hlos_vote.ab = applied_ab_bw;
|
||||
cpas_core->axi_port[i].applied_bw.hlos_vote.ib = applied_ib_bw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -566,13 +627,27 @@ static bool cam_cpas_is_new_rt_bw_lower(
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
temp_axi_port = &cpas_core->axi_port[i];
|
||||
|
||||
if (temp_axi_port->is_rt) {
|
||||
CAM_DBG(CAM_PERF, "Port %s applied %llu new %llu",
|
||||
temp_axi_port->axi_port_name, temp_axi_port->applied_ab_bw,
|
||||
temp_axi_port->ab_bw);
|
||||
if (!temp_axi_port->is_rt)
|
||||
continue;
|
||||
|
||||
applied_total += temp_axi_port->applied_ab_bw;
|
||||
new_total += temp_axi_port->ab_bw;
|
||||
if (temp_axi_port->bus_client.common_data.is_drv_port) {
|
||||
CAM_DBG(CAM_PERF, "Port %s DRV ab applied [%llu %llu] new [%llu %llu]",
|
||||
temp_axi_port->axi_port_name,
|
||||
temp_axi_port->applied_bw.drv_vote.high.ab,
|
||||
temp_axi_port->applied_bw.drv_vote.low.ab,
|
||||
temp_axi_port->curr_bw.drv_vote.high.ab,
|
||||
temp_axi_port->curr_bw.drv_vote.low.ab);
|
||||
|
||||
applied_total += temp_axi_port->applied_bw.drv_vote.high.ab;
|
||||
new_total += temp_axi_port->curr_bw.drv_vote.high.ab;
|
||||
} else {
|
||||
CAM_DBG(CAM_PERF, "Port %s HLOS ab applied %llu new %llu",
|
||||
temp_axi_port->axi_port_name,
|
||||
temp_axi_port->applied_bw.hlos_vote.ab,
|
||||
temp_axi_port->curr_bw.hlos_vote.ab);
|
||||
|
||||
applied_total += temp_axi_port->applied_bw.hlos_vote.ab;
|
||||
new_total += temp_axi_port->curr_bw.hlos_vote.ab;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,25 +968,17 @@ static int cam_cpas_axi_consolidate_path_votes(
|
||||
*/
|
||||
cons_entry_found = false;
|
||||
for (l = 0; l < con_axi_vote->num_paths; l++) {
|
||||
if ((con_axi_vote->axi_path[l]
|
||||
.path_data_type == k) &&
|
||||
(con_axi_vote->axi_path[l]
|
||||
.transac_type == transac_type)) {
|
||||
if ((con_axi_vote->axi_path[l].path_data_type == k) &&
|
||||
(con_axi_vote->axi_path[l].transac_type == transac_type)) {
|
||||
cons_entry_found = true;
|
||||
con_axi_vote->axi_path[l]
|
||||
.camnoc_bw +=
|
||||
axi_vote->axi_path[i]
|
||||
.camnoc_bw;
|
||||
con_axi_vote->axi_path[l].camnoc_bw +=
|
||||
axi_vote->axi_path[i].camnoc_bw;
|
||||
|
||||
con_axi_vote->axi_path[l]
|
||||
.mnoc_ab_bw +=
|
||||
axi_vote->axi_path[i]
|
||||
.mnoc_ab_bw;
|
||||
con_axi_vote->axi_path[l].mnoc_ab_bw +=
|
||||
axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
|
||||
con_axi_vote->axi_path[l]
|
||||
.mnoc_ib_bw +=
|
||||
axi_vote->axi_path[i]
|
||||
.mnoc_ib_bw;
|
||||
con_axi_vote->axi_path[l].mnoc_ib_bw +=
|
||||
axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -920,12 +987,10 @@ static int cam_cpas_axi_consolidate_path_votes(
|
||||
if (!cons_entry_found) {
|
||||
axi_path->path_data_type = k;
|
||||
axi_path->transac_type = transac_type;
|
||||
axi_path->camnoc_bw =
|
||||
axi_vote->axi_path[i].camnoc_bw;
|
||||
axi_path->mnoc_ab_bw =
|
||||
axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
axi_path->mnoc_ib_bw =
|
||||
axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
axi_path->camnoc_bw = axi_vote->axi_path[i].camnoc_bw;
|
||||
axi_path->mnoc_ab_bw = axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
axi_path->mnoc_ib_bw = axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
axi_path->vote_level = axi_vote->axi_path[i].vote_level;
|
||||
con_axi_vote->num_paths++;
|
||||
}
|
||||
break;
|
||||
@@ -947,30 +1012,51 @@ static int cam_cpas_axi_consolidate_path_votes(
|
||||
static int cam_cpas_update_axi_vote_bw(
|
||||
struct cam_hw_info *cpas_hw,
|
||||
struct cam_cpas_tree_node *cpas_tree_node,
|
||||
int drv_voting_idx,
|
||||
bool *mnoc_axi_port_updated,
|
||||
bool *camnoc_axi_port_updated)
|
||||
{
|
||||
int i, axi_port_idx = -1;
|
||||
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;
|
||||
bool is_mnoc_updated = false;
|
||||
|
||||
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);
|
||||
for (i = 0; i < CAM_CPAS_MAX_DRV_PORTS; i++) {
|
||||
axi_port_idx = cpas_tree_node->axi_port_idx_arr[i];
|
||||
if ((axi_port_idx < 0) || (i != drv_voting_idx))
|
||||
continue;
|
||||
|
||||
if (axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d drv_idx: %d", axi_port_idx, i);
|
||||
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;
|
||||
memcpy(&cpas_core->axi_port[axi_port_idx].curr_bw, &cpas_tree_node->bw_info[i],
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
|
||||
/* Add low value to high for drv */
|
||||
if (i > CAM_CPAS_PORT_HLOS_DRV) {
|
||||
cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ab +=
|
||||
cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ab;
|
||||
cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.high.ib +=
|
||||
cpas_core->axi_port[axi_port_idx].curr_bw.drv_vote.low.ib;
|
||||
}
|
||||
|
||||
mnoc_axi_port_updated[axi_port_idx] = true;
|
||||
is_mnoc_updated = true;
|
||||
}
|
||||
|
||||
if (!is_mnoc_updated) {
|
||||
CAM_ERR(CAM_CPAS, "No mnoc port was updated");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV]]
|
||||
.camnoc_bw = cpas_tree_node->camnoc_bw;
|
||||
camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -1025,7 +1111,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate(
|
||||
else
|
||||
camnoc_bw = 0;
|
||||
|
||||
rc = cam_cpas_util_vote_bus_client_bw(
|
||||
rc = cam_cpas_util_vote_hlos_bus_client_bw(
|
||||
&camnoc_axi_port->bus_client,
|
||||
0, camnoc_bw, true, &applied_ab, &applied_ib);
|
||||
|
||||
@@ -1038,8 +1124,9 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate(
|
||||
camnoc_bw, rc);
|
||||
break;
|
||||
}
|
||||
camnoc_axi_port->applied_ab_bw = applied_ab;
|
||||
camnoc_axi_port->applied_ib_bw = applied_ib;
|
||||
|
||||
camnoc_axi_port->applied_bw.hlos_vote.ab = applied_ab;
|
||||
camnoc_axi_port->applied_bw.hlos_vote.ib = applied_ib;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1047,7 +1134,7 @@ static int cam_cpas_camnoc_set_vote_axi_clk_rate(
|
||||
static int cam_cpas_util_apply_client_axi_vote(
|
||||
struct cam_hw_info *cpas_hw,
|
||||
struct cam_cpas_client *cpas_client,
|
||||
struct cam_axi_vote *axi_vote)
|
||||
struct cam_axi_vote *axi_vote, uint32_t apply_type)
|
||||
{
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
@@ -1060,13 +1147,13 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
uint32_t path_data_type;
|
||||
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;
|
||||
int rc = 0, i = 0;
|
||||
uint64_t applied_ab = 0, applied_ib = 0;
|
||||
uint64_t curr_camnoc_old = 0, par_camnoc_old = 0;
|
||||
struct cam_cpas_axi_bw_info curr_mnoc_old = {0}, par_mnoc_old = {0}, curr_port_bw = {0},
|
||||
applied_port_bw = {0};
|
||||
int rc = 0, i = 0, drv_voting_idx;
|
||||
bool apply_smart_qos = false;
|
||||
bool rt_bw_updated = false;
|
||||
bool camnoc_unchanged = false;
|
||||
|
||||
mutex_lock(&cpas_core->tree_lock);
|
||||
if (!cpas_client->tree_node_valid) {
|
||||
@@ -1076,6 +1163,9 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
* not called from hw_update_axi_vote
|
||||
*/
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
if (cpas_core->axi_port[i].bus_client.common_data.is_drv_port)
|
||||
continue;
|
||||
|
||||
if (axi_vote->axi_path[0].mnoc_ab_bw) {
|
||||
/* start case */
|
||||
cpas_core->axi_port[i].additional_bw +=
|
||||
@@ -1114,66 +1204,119 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
|
||||
con_axi_vote = &cpas_client->axi_vote;
|
||||
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote",
|
||||
con_axi_vote);
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote", con_axi_vote);
|
||||
|
||||
/* Traverse through node tree and update bw vote values */
|
||||
for (i = 0; i < con_axi_vote->num_paths; i++) {
|
||||
path_data_type =
|
||||
con_axi_vote->axi_path[i].path_data_type;
|
||||
transac_type =
|
||||
con_axi_vote->axi_path[i].transac_type;
|
||||
curr_tree_node = cpas_client->tree_node[path_data_type]
|
||||
[transac_type];
|
||||
path_data_type = con_axi_vote->axi_path[i].path_data_type;
|
||||
transac_type = con_axi_vote->axi_path[i].transac_type;
|
||||
curr_tree_node = cpas_client->tree_node[path_data_type][transac_type];
|
||||
drv_voting_idx = curr_tree_node->drv_voting_idx;
|
||||
|
||||
if (con_axi_vote->axi_path[i].mnoc_ab_bw == 0)
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw =
|
||||
con_axi_vote->axi_path[i].camnoc_bw;
|
||||
if (cpas_core->force_hlos_drv)
|
||||
drv_voting_idx = CAM_CPAS_PORT_HLOS_DRV;
|
||||
|
||||
if (con_axi_vote->axi_path[i].camnoc_bw == 0)
|
||||
con_axi_vote->axi_path[i].camnoc_bw =
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
if (curr_tree_node->camnoc_bw == con_axi_vote->axi_path[i].camnoc_bw)
|
||||
camnoc_unchanged = true;
|
||||
|
||||
if ((curr_tree_node->camnoc_bw ==
|
||||
con_axi_vote->axi_path[i].camnoc_bw) &&
|
||||
(curr_tree_node->mnoc_ab_bw ==
|
||||
curr_camnoc_old = curr_tree_node->camnoc_bw;
|
||||
curr_tree_node->camnoc_bw = con_axi_vote->axi_path[i].camnoc_bw;
|
||||
memcpy(&curr_mnoc_old, &curr_tree_node->bw_info[drv_voting_idx],
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
|
||||
if (soc_private->enable_cam_ddr_drv && (con_axi_vote->axi_path[i].vote_level ==
|
||||
CAM_CPAS_VOTE_LEVEL_HIGH)) {
|
||||
if (camnoc_unchanged &&
|
||||
(curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab ==
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw) &&
|
||||
(curr_tree_node->mnoc_ib_bw ==
|
||||
(curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib ==
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw))
|
||||
continue;
|
||||
|
||||
curr_camnoc_old = curr_tree_node->camnoc_bw;
|
||||
curr_mnoc_ab_old = curr_tree_node->mnoc_ab_bw;
|
||||
curr_mnoc_ib_old = curr_tree_node->mnoc_ib_bw;
|
||||
curr_tree_node->camnoc_bw =
|
||||
con_axi_vote->axi_path[i].camnoc_bw;
|
||||
curr_tree_node->mnoc_ab_bw =
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab =
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
curr_tree_node->mnoc_ib_bw =
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib =
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab = 0;
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib = 0;
|
||||
} else {
|
||||
if ((drv_voting_idx > CAM_CPAS_PORT_HLOS_DRV) &&
|
||||
!cpas_core->force_hlos_drv) {
|
||||
if (camnoc_unchanged &&
|
||||
(curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab ==
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw) &&
|
||||
(curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib ==
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw))
|
||||
continue;
|
||||
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab =
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib =
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab = 0;
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib = 0;
|
||||
} else {
|
||||
if (camnoc_unchanged &&
|
||||
(curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab ==
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw) &&
|
||||
(curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib ==
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw))
|
||||
continue;
|
||||
|
||||
curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab =
|
||||
con_axi_vote->axi_path[i].mnoc_ab_bw;
|
||||
curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib =
|
||||
con_axi_vote->axi_path[i].mnoc_ib_bw;
|
||||
}
|
||||
}
|
||||
|
||||
while (curr_tree_node->parent_node) {
|
||||
par_tree_node = curr_tree_node->parent_node;
|
||||
par_camnoc_old = par_tree_node->camnoc_bw;
|
||||
par_mnoc_ab_old = par_tree_node->mnoc_ab_bw;
|
||||
par_mnoc_ib_old = par_tree_node->mnoc_ib_bw;
|
||||
par_tree_node->mnoc_ab_bw -= curr_mnoc_ab_old;
|
||||
par_tree_node->mnoc_ab_bw += curr_tree_node->mnoc_ab_bw;
|
||||
par_tree_node->mnoc_ib_bw -= curr_mnoc_ib_old;
|
||||
par_tree_node->mnoc_ib_bw += curr_tree_node->mnoc_ib_bw;
|
||||
memcpy(&par_mnoc_old, &par_tree_node->bw_info[drv_voting_idx],
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
|
||||
if (par_tree_node->merge_type ==
|
||||
CAM_CPAS_TRAFFIC_MERGE_SUM) {
|
||||
par_tree_node->camnoc_bw -=
|
||||
curr_camnoc_old;
|
||||
par_tree_node->camnoc_bw +=
|
||||
curr_tree_node->camnoc_bw;
|
||||
/*
|
||||
* Remove contribution of current node old bw from parent,
|
||||
* then add new bw of current level to the parent
|
||||
*/
|
||||
if (drv_voting_idx > CAM_CPAS_PORT_HLOS_DRV) {
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab -=
|
||||
curr_mnoc_old.drv_vote.high.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib -=
|
||||
curr_mnoc_old.drv_vote.high.ib;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab -=
|
||||
curr_mnoc_old.drv_vote.low.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib -=
|
||||
curr_mnoc_old.drv_vote.low.ib;
|
||||
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.high.ib;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].drv_vote.low.ib;
|
||||
} else {
|
||||
par_tree_node->bw_info[drv_voting_idx].hlos_vote.ab -=
|
||||
curr_mnoc_old.hlos_vote.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].hlos_vote.ib -=
|
||||
curr_mnoc_old.hlos_vote.ib;
|
||||
|
||||
par_tree_node->bw_info[drv_voting_idx].hlos_vote.ab +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ab;
|
||||
par_tree_node->bw_info[drv_voting_idx].hlos_vote.ib +=
|
||||
curr_tree_node->bw_info[drv_voting_idx].hlos_vote.ib;
|
||||
}
|
||||
|
||||
if (par_tree_node->merge_type == CAM_CPAS_TRAFFIC_MERGE_SUM) {
|
||||
par_tree_node->camnoc_bw -= curr_camnoc_old;
|
||||
par_tree_node->camnoc_bw += curr_tree_node->camnoc_bw;
|
||||
} else if (par_tree_node->merge_type ==
|
||||
CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE) {
|
||||
par_tree_node->camnoc_bw -=
|
||||
(curr_camnoc_old / 2);
|
||||
par_tree_node->camnoc_bw +=
|
||||
(curr_tree_node->camnoc_bw / 2);
|
||||
par_tree_node->camnoc_bw -= (curr_camnoc_old / 2);
|
||||
par_tree_node->camnoc_bw += (curr_tree_node->camnoc_bw / 2);
|
||||
} else {
|
||||
CAM_ERR(CAM_CPAS, "Invalid Merge type");
|
||||
rc = -EINVAL;
|
||||
@@ -1181,29 +1324,18 @@ static int cam_cpas_util_apply_client_axi_vote(
|
||||
}
|
||||
|
||||
if (!par_tree_node->parent_node) {
|
||||
if ((par_tree_node->axi_port_idx < 0) ||
|
||||
(par_tree_node->axi_port_idx >=
|
||||
CAM_CPAS_MAX_AXI_PORTS)) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"AXI port index invalid");
|
||||
rc = -EINVAL;
|
||||
goto unlock_tree;
|
||||
}
|
||||
rc = cam_cpas_update_axi_vote_bw(cpas_hw,
|
||||
par_tree_node,
|
||||
mnoc_axi_port_updated,
|
||||
rc = cam_cpas_update_axi_vote_bw(cpas_hw, par_tree_node,
|
||||
drv_voting_idx, mnoc_axi_port_updated,
|
||||
camnoc_axi_port_updated);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Update Vote failed");
|
||||
CAM_ERR(CAM_CPAS, "Update Vote failed");
|
||||
goto unlock_tree;
|
||||
}
|
||||
}
|
||||
|
||||
curr_tree_node = par_tree_node;
|
||||
curr_camnoc_old = par_camnoc_old;
|
||||
curr_mnoc_ab_old = par_mnoc_ab_old;
|
||||
curr_mnoc_ib_old = par_mnoc_ib_old;
|
||||
memcpy(&curr_mnoc_old, &par_mnoc_old, sizeof(struct cam_cpas_axi_bw_info));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1251,42 +1383,115 @@ vote_start_clients:
|
||||
else
|
||||
continue;
|
||||
|
||||
memcpy(&curr_port_bw, &mnoc_axi_port->curr_bw, sizeof(struct cam_cpas_axi_bw_info));
|
||||
|
||||
if (mnoc_axi_port->bus_client.common_data.is_drv_port) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"Port[%s] : ab=%lld ib=%lld additional=%lld, streamon_clients=%d",
|
||||
mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw,
|
||||
mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw,
|
||||
"Port[%s] :DRV high [%lld %lld] low [%lld %lld] streamon_clients=%d",
|
||||
mnoc_axi_port->axi_port_name,
|
||||
mnoc_axi_port->curr_bw.drv_vote.high.ab,
|
||||
mnoc_axi_port->curr_bw.drv_vote.high.ib,
|
||||
mnoc_axi_port->curr_bw.drv_vote.low.ab,
|
||||
mnoc_axi_port->curr_bw.drv_vote.low.ib,
|
||||
cpas_core->streamon_clients);
|
||||
|
||||
if (mnoc_axi_port->ab_bw)
|
||||
mnoc_ab_bw = mnoc_axi_port->ab_bw;
|
||||
else if (mnoc_axi_port->additional_bw)
|
||||
mnoc_ab_bw = mnoc_axi_port->additional_bw;
|
||||
else if (cpas_core->streamon_clients)
|
||||
mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW;
|
||||
else
|
||||
mnoc_ab_bw = 0;
|
||||
if (!mnoc_axi_port->ib_bw_voting_needed) {
|
||||
curr_port_bw.drv_vote.high.ib = 0;
|
||||
curr_port_bw.drv_vote.low.ib = 0;
|
||||
}
|
||||
|
||||
if (cpas_core->axi_port[i].ib_bw_voting_needed)
|
||||
mnoc_ib_bw = mnoc_axi_port->ib_bw;
|
||||
else
|
||||
mnoc_ib_bw = 0;
|
||||
|
||||
rc = cam_cpas_util_vote_bus_client_bw(
|
||||
&mnoc_axi_port->bus_client,
|
||||
mnoc_ab_bw, mnoc_ib_bw, false, &applied_ab,
|
||||
&applied_ib);
|
||||
/* Vote bw on appropriate bus id */
|
||||
rc = cam_cpas_util_vote_drv_bus_client_bw(&mnoc_axi_port->bus_client,
|
||||
&curr_port_bw, &applied_port_bw);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
|
||||
mnoc_ab_bw, mnoc_ib_bw, rc);
|
||||
CAM_ERR(CAM_CPAS, "Failed in mnoc vote for %s rc=%d",
|
||||
mnoc_axi_port->axi_port_name, rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
mnoc_axi_port->applied_ab_bw = applied_ab;
|
||||
mnoc_axi_port->applied_ib_bw = applied_ib;
|
||||
|
||||
/* Do start/stop/channel switch based on apply type */
|
||||
if ((apply_type == CAM_CPAS_APPLY_TYPE_START) &&
|
||||
!mnoc_axi_port->is_drv_started) {
|
||||
rc = cam_cpas_start_drv_for_dev(mnoc_axi_port->cam_rsc_dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Port[%s] failed in DRV start rc:%d",
|
||||
mnoc_axi_port->axi_port_name, rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
rc = cam_cpas_camnoc_set_vote_axi_clk_rate(
|
||||
cpas_hw, camnoc_axi_port_updated);
|
||||
CAM_DBG(CAM_CPAS, "Started rsc dev %s mnoc port:%s",
|
||||
dev_name(mnoc_axi_port->cam_rsc_dev),
|
||||
mnoc_axi_port->axi_port_name);
|
||||
mnoc_axi_port->is_drv_started = true;
|
||||
} else if ((apply_type == CAM_CPAS_APPLY_TYPE_STOP) &&
|
||||
mnoc_axi_port->is_drv_started &&
|
||||
(applied_port_bw.drv_vote.high.ab == 0) &&
|
||||
(applied_port_bw.drv_vote.high.ib == 0) &&
|
||||
(applied_port_bw.drv_vote.low.ab == 0) &&
|
||||
(applied_port_bw.drv_vote.low.ib == 0)) {
|
||||
rc = cam_cpas_stop_drv_for_dev(mnoc_axi_port->cam_rsc_dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Port[%s] failed in DRV stop rc:%d",
|
||||
mnoc_axi_port->axi_port_name, rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_CPAS, "Stopped rsc dev %s mnoc port:%s",
|
||||
dev_name(mnoc_axi_port->cam_rsc_dev),
|
||||
mnoc_axi_port->axi_port_name);
|
||||
mnoc_axi_port->is_drv_started = false;
|
||||
} else {
|
||||
if (mnoc_axi_port->is_drv_started) {
|
||||
rc = cam_cpas_drv_channel_switch_for_dev(
|
||||
mnoc_axi_port->cam_rsc_dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Port[%s] failed in channel switch rc:%d",
|
||||
mnoc_axi_port->axi_port_name, rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"Channel switch for rsc dev %s mnoc port:%s",
|
||||
dev_name(mnoc_axi_port->cam_rsc_dev),
|
||||
mnoc_axi_port->axi_port_name);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"Port[%s] :HLOS ab=%lld ib=%lld additional=%lld, streamon_clients=%d",
|
||||
mnoc_axi_port->axi_port_name, mnoc_axi_port->curr_bw.hlos_vote.ab,
|
||||
mnoc_axi_port->curr_bw.hlos_vote.ib, mnoc_axi_port->additional_bw,
|
||||
cpas_core->streamon_clients);
|
||||
|
||||
if (!mnoc_axi_port->curr_bw.hlos_vote.ab) {
|
||||
if (mnoc_axi_port->additional_bw)
|
||||
curr_port_bw.hlos_vote.ab = mnoc_axi_port->additional_bw;
|
||||
else if (cpas_core->streamon_clients)
|
||||
curr_port_bw.hlos_vote.ab = CAM_CPAS_DEFAULT_AXI_BW;
|
||||
else
|
||||
curr_port_bw.hlos_vote.ab = 0;
|
||||
}
|
||||
|
||||
if (!mnoc_axi_port->ib_bw_voting_needed)
|
||||
curr_port_bw.hlos_vote.ib = 0;
|
||||
|
||||
rc = cam_cpas_util_vote_hlos_bus_client_bw(&mnoc_axi_port->bus_client,
|
||||
curr_port_bw.hlos_vote.ab, curr_port_bw.hlos_vote.ib, false,
|
||||
&applied_port_bw.hlos_vote.ab, &applied_port_bw.hlos_vote.ib);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in mnoc vote for %s rc=%d",
|
||||
mnoc_axi_port->axi_port_name, rc);
|
||||
goto unlock_tree;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&mnoc_axi_port->applied_bw, &applied_port_bw,
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
}
|
||||
|
||||
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);
|
||||
goto unlock_tree;
|
||||
@@ -1317,8 +1522,9 @@ static int cam_cpas_util_apply_default_axi_vote(
|
||||
|
||||
mutex_lock(&cpas_core->tree_lock);
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
if (!cpas_core->axi_port[i].ab_bw ||
|
||||
!cpas_core->axi_port[i].ib_bw)
|
||||
if ((!cpas_core->axi_port[i].bus_client.common_data.is_drv_port) &&
|
||||
(!cpas_core->axi_port[i].curr_bw.hlos_vote.ab ||
|
||||
!cpas_core->axi_port[i].curr_bw.hlos_vote.ib))
|
||||
axi_port = &cpas_core->axi_port[i];
|
||||
else
|
||||
continue;
|
||||
@@ -1331,9 +1537,9 @@ static int cam_cpas_util_apply_default_axi_vote(
|
||||
CAM_DBG(CAM_CPAS, "Port=[%s] :ab[%llu] ib[%llu]",
|
||||
axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw);
|
||||
|
||||
rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client,
|
||||
mnoc_ab_bw, mnoc_ib_bw, false, &axi_port->applied_ab_bw,
|
||||
&axi_port->applied_ib_bw);
|
||||
rc = cam_cpas_util_vote_hlos_bus_client_bw(&axi_port->bus_client,
|
||||
mnoc_ab_bw, mnoc_ib_bw, false, &axi_port->applied_bw.hlos_vote.ab,
|
||||
&axi_port->applied_bw.hlos_vote.ib);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
|
||||
@@ -1401,7 +1607,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw,
|
||||
"Translated Vote", axi_vote);
|
||||
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
|
||||
cpas_core->cpas_client[client_indx], axi_vote);
|
||||
cpas_core->cpas_client[client_indx], axi_vote, CAM_CPAS_APPLY_TYPE_UPDATE);
|
||||
|
||||
/* Log an entry whenever there is an AXI update - after updating */
|
||||
cam_cpas_update_monitor_array(cpas_hw, "CPAS AXI post-update",
|
||||
@@ -1610,6 +1816,9 @@ static int cam_cpas_util_create_vote_all_paths(
|
||||
axi_path->camnoc_bw = camnoc_bw;
|
||||
axi_path->mnoc_ab_bw = mnoc_ab_bw;
|
||||
axi_path->mnoc_ib_bw = mnoc_ib_bw;
|
||||
if (cpas_client->tree_node[j][i]->drv_voting_idx >
|
||||
CAM_CPAS_PORT_HLOS_DRV)
|
||||
axi_path->vote_level = CAM_CPAS_VOTE_LEVEL_LOW;
|
||||
|
||||
axi_vote->num_paths++;
|
||||
}
|
||||
@@ -1734,15 +1943,17 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
|
||||
goto remove_ahb_vote;
|
||||
}
|
||||
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote",
|
||||
&axi_vote);
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", &axi_vote);
|
||||
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
|
||||
cpas_client, &axi_vote);
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote,
|
||||
CAM_CPAS_APPLY_TYPE_START);
|
||||
if (rc)
|
||||
goto remove_ahb_vote;
|
||||
|
||||
if (cpas_core->streamon_clients == 0) {
|
||||
if (cpas_core->force_hlos_drv)
|
||||
soc_private->enable_cam_ddr_drv = false;
|
||||
|
||||
rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true);
|
||||
if (rc)
|
||||
goto remove_ahb_vote;
|
||||
@@ -1821,8 +2032,8 @@ remove_axi_vote:
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start fail Vote",
|
||||
&axi_vote);
|
||||
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
|
||||
cpas_client, &axi_vote);
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote,
|
||||
CAM_CPAS_APPLY_TYPE_STOP);
|
||||
if (rc)
|
||||
CAM_ERR(CAM_CPAS, "Unable remove votes rc: %d", rc);
|
||||
|
||||
@@ -1980,13 +2191,14 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
|
||||
|
||||
cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Stop Vote", &axi_vote);
|
||||
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw,
|
||||
cpas_client, &axi_vote);
|
||||
rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, cpas_client, &axi_vote,
|
||||
CAM_CPAS_APPLY_TYPE_STOP);
|
||||
if (rc)
|
||||
goto done;
|
||||
|
||||
if (cpas_core->streamon_clients == 0)
|
||||
rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, false);
|
||||
|
||||
done:
|
||||
mutex_unlock(&cpas_core->client_mutex[client_indx]);
|
||||
mutex_unlock(&cpas_hw->hw_mutex);
|
||||
@@ -2228,14 +2440,26 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
|
||||
}
|
||||
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]",
|
||||
if (cpas_core->axi_port[i].bus_client.common_data.is_drv_port) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"[%s] DRV applied: high [%llu %llu] low[%llu %llu] new: high [%llu %llu] low [%llu %llu]",
|
||||
cpas_core->axi_port[i].axi_port_name,
|
||||
cpas_core->axi_port[i].ab_bw,
|
||||
cpas_core->axi_port[i].ib_bw,
|
||||
cpas_core->axi_port[i].additional_bw,
|
||||
cpas_core->axi_port[i].applied_ab_bw,
|
||||
cpas_core->axi_port[i].applied_ib_bw);
|
||||
cpas_core->axi_port[i].applied_bw.drv_vote.high.ab,
|
||||
cpas_core->axi_port[i].applied_bw.drv_vote.high.ib,
|
||||
cpas_core->axi_port[i].applied_bw.drv_vote.low.ab,
|
||||
cpas_core->axi_port[i].applied_bw.drv_vote.low.ib,
|
||||
cpas_core->axi_port[i].curr_bw.drv_vote.high.ab,
|
||||
cpas_core->axi_port[i].curr_bw.drv_vote.high.ib,
|
||||
cpas_core->axi_port[i].curr_bw.drv_vote.low.ab,
|
||||
cpas_core->axi_port[i].curr_bw.drv_vote.low.ib);
|
||||
} else {
|
||||
CAM_INFO(CAM_PERF, "Port %s HLOS applied [%llu %llu] new [%llu %llu]",
|
||||
cpas_core->axi_port[i].axi_port_name,
|
||||
cpas_core->axi_port[i].applied_bw.hlos_vote.ab,
|
||||
cpas_core->axi_port[i].applied_bw.hlos_vote.ib,
|
||||
cpas_core->axi_port[i].curr_bw.hlos_vote.ab,
|
||||
cpas_core->axi_port[i].curr_bw.hlos_vote.ib);
|
||||
}
|
||||
}
|
||||
|
||||
if (soc_private->control_camnoc_axi_clk) {
|
||||
@@ -2246,11 +2470,11 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"[%s] ab_bw[%lld] ib_bw[%lld] additional_bw[%lld] applied_ab[%lld] applied_ib[%lld]",
|
||||
cpas_core->camnoc_axi_port[i].axi_port_name,
|
||||
cpas_core->camnoc_axi_port[i].ab_bw,
|
||||
cpas_core->camnoc_axi_port[i].ib_bw,
|
||||
cpas_core->camnoc_axi_port[i].curr_bw.hlos_vote.ab,
|
||||
cpas_core->camnoc_axi_port[i].curr_bw.hlos_vote.ib,
|
||||
cpas_core->camnoc_axi_port[i].additional_bw,
|
||||
cpas_core->camnoc_axi_port[i].applied_ab_bw,
|
||||
cpas_core->camnoc_axi_port[i].applied_ib_bw);
|
||||
cpas_core->camnoc_axi_port[i].applied_bw.hlos_vote.ab,
|
||||
cpas_core->camnoc_axi_port[i].applied_bw.hlos_vote.ib);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2266,18 +2490,42 @@ static int cam_cpas_log_vote(struct cam_hw_info *cpas_hw)
|
||||
for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) {
|
||||
if (!soc_private->tree_node[i])
|
||||
continue;
|
||||
|
||||
curr_node = soc_private->tree_node[i];
|
||||
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"[%s] Cell[%d] level[%d] PortIdx[%d][%d] camnoc_bw[%d %d %lld %lld] mnoc_bw[%lld %lld]",
|
||||
curr_node->node_name, curr_node->cell_idx,
|
||||
curr_node->level_idx, curr_node->axi_port_idx,
|
||||
curr_node->level_idx,
|
||||
curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV],
|
||||
curr_node->camnoc_axi_port_idx,
|
||||
curr_node->camnoc_max_needed,
|
||||
curr_node->bus_width_factor,
|
||||
curr_node->camnoc_bw,
|
||||
curr_node->camnoc_bw * curr_node->bus_width_factor,
|
||||
curr_node->mnoc_ab_bw, curr_node->mnoc_ib_bw);
|
||||
curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_HLOS_DRV].hlos_vote.ib);
|
||||
|
||||
if (!soc_private->enable_cam_ddr_drv)
|
||||
continue;
|
||||
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"DRV PortIdx[%d][%d][%d] mnoc_bw DRV_0: [high[%lld %lld] low[%lld %lld]] DRV_1: [high[%lld %lld] low[%lld %lld]] DRV_2: [high[%lld %lld] low[%lld %lld]]",
|
||||
curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_0],
|
||||
curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_1],
|
||||
curr_node->axi_port_idx_arr[CAM_CPAS_PORT_DRV_2],
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.high.ib,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_0].drv_vote.low.ib,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.high.ib,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_1].drv_vote.low.ib,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.high.ib,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.ab,
|
||||
curr_node->bw_info[CAM_CPAS_PORT_DRV_2].drv_vote.low.ib);
|
||||
}
|
||||
|
||||
cam_cpas_dump_monitor_array(cpas_hw);
|
||||
@@ -2322,15 +2570,13 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
|
||||
entry->identifier_value = identifier_value;
|
||||
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
entry->axi_info[i].axi_port_name =
|
||||
cpas_core->axi_port[i].axi_port_name;
|
||||
entry->axi_info[i].ab_bw = cpas_core->axi_port[i].ab_bw;
|
||||
entry->axi_info[i].ib_bw = cpas_core->axi_port[i].ib_bw;
|
||||
entry->axi_info[i].axi_port_name = cpas_core->axi_port[i].axi_port_name;
|
||||
memcpy(&entry->axi_info[i].curr_bw, &cpas_core->axi_port[i].curr_bw,
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
entry->axi_info[i].camnoc_bw = cpas_core->axi_port[i].camnoc_bw;
|
||||
entry->axi_info[i].applied_ab_bw =
|
||||
cpas_core->axi_port[i].applied_ab_bw;
|
||||
entry->axi_info[i].applied_ib_bw =
|
||||
cpas_core->axi_port[i].applied_ib_bw;
|
||||
memcpy(&entry->axi_info[i].applied_bw, &cpas_core->axi_port[i].applied_bw,
|
||||
sizeof(struct cam_cpas_axi_bw_info));
|
||||
entry->axi_info[i].is_drv_started = cpas_core->axi_port[i].is_drv_started;
|
||||
}
|
||||
|
||||
entry->applied_camnoc_clk = cpas_core->applied_camnoc_axi_rate;
|
||||
@@ -2463,11 +2709,24 @@ static void cam_cpas_dump_monitor_array(
|
||||
entry->applied_camnoc_clk, entry->applied_ahb_level);
|
||||
|
||||
for (j = 0; j < cpas_core->num_axi_ports; j++) {
|
||||
if ((entry->axi_info[j].applied_bw.vote_type == CAM_CPAS_VOTE_TYPE_DRV) &&
|
||||
!cpas_core->force_hlos_drv)
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"MNOC BW [%s] : ab=%lld, ib=%lld, camnoc=%lld",
|
||||
"BW [%s] : DRV started:%s high=[%lld %lld], low=[%lld %lld], camnoc=%lld",
|
||||
entry->axi_info[j].axi_port_name,
|
||||
entry->axi_info[j].applied_ab_bw,
|
||||
entry->axi_info[j].applied_ib_bw,
|
||||
CAM_BOOL_TO_YESNO(entry->axi_info[j].is_drv_started),
|
||||
entry->axi_info[j].applied_bw.drv_vote.high.ab,
|
||||
entry->axi_info[j].applied_bw.drv_vote.high.ib,
|
||||
entry->axi_info[j].applied_bw.drv_vote.low.ab,
|
||||
entry->axi_info[j].applied_bw.drv_vote.low.ib,
|
||||
entry->axi_info[j].camnoc_bw);
|
||||
|
||||
else
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"BW [%s] : HLOS ab=%lld, ib=%lld, DRV high_ab=%lld, high_ib=%lld, low_ab=%lld, low_ib=%lld, camnoc=%lld",
|
||||
entry->axi_info[j].axi_port_name,
|
||||
entry->axi_info[j].applied_bw.hlos_vote.ab,
|
||||
entry->axi_info[j].applied_bw.hlos_vote.ib,
|
||||
entry->axi_info[j].camnoc_bw);
|
||||
}
|
||||
|
||||
@@ -2686,6 +2945,89 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_hw_csid_input_core_info_update(struct cam_hw_info *cpas_hw,
|
||||
int csid_idx, int sfe_idx, bool set_port)
|
||||
{
|
||||
int i, j, rc = 0;
|
||||
char client_name[CAM_HW_IDENTIFIER_LENGTH + 3];
|
||||
int32_t client_indx = -1;
|
||||
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
struct cam_cpas_tree_node *tree_node = NULL;
|
||||
|
||||
if (!soc_private->enable_cam_ddr_drv || cpas_core->force_hlos_drv)
|
||||
return 0;
|
||||
|
||||
if ((csid_idx < 0) || (sfe_idx < 0)) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid core info csid:%d sfe:%d", csid_idx, sfe_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(client_name, sizeof(client_name), "%s%d", "sfe", sfe_idx);
|
||||
|
||||
rc = cam_common_util_get_string_index(soc_private->client_name,
|
||||
soc_private->num_clients, client_name, &client_indx);
|
||||
|
||||
if (!cpas_core->cpas_client[client_indx]->is_drv_dyn)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < CAM_CPAS_PATH_DATA_MAX; i++) {
|
||||
for (j = 0; j < CAM_CPAS_TRANSACTION_MAX; j++) {
|
||||
tree_node = cpas_core->cpas_client[client_indx]->tree_node[i][j];
|
||||
if (!tree_node)
|
||||
continue;
|
||||
|
||||
if (set_port)
|
||||
tree_node->drv_voting_idx = CAM_CPAS_PORT_DRV_0 + csid_idx;
|
||||
else
|
||||
tree_node->drv_voting_idx = CAM_CPAS_PORT_DRV_DYN;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_hw_csid_process_resume(struct cam_hw_info *cpas_hw, uint32_t csid_idx)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
struct cam_cpas_private_soc *soc_private =
|
||||
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
|
||||
if (!soc_private->enable_cam_ddr_drv)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < cpas_core->num_axi_ports; i++) {
|
||||
if (!cpas_core->axi_port[i].bus_client.common_data.is_drv_port ||
|
||||
!cpas_core->axi_port[i].is_drv_started ||
|
||||
(cpas_core->axi_port[i].drv_idx != (CAM_CPAS_PORT_DRV_0 + csid_idx)))
|
||||
continue;
|
||||
|
||||
/* Apply last applied bw again to applicable DRV port */
|
||||
rc = cam_cpas_util_vote_drv_bus_client_bw(&cpas_core->axi_port[i].bus_client,
|
||||
&cpas_core->axi_port[i].applied_bw, &cpas_core->axi_port[i].applied_bw);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in BW update on resume rc:%d", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Trigger channel switch for RSC dev */
|
||||
rc = cam_cpas_drv_channel_switch_for_dev(cpas_core->axi_port[i].cam_rsc_dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Port[%s] failed in channel switch during resume rc:%d",
|
||||
cpas_core->axi_port[i].axi_port_name, rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_hw_process_cmd(void *hw_priv,
|
||||
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
|
||||
{
|
||||
@@ -2872,6 +3214,33 @@ static int cam_cpas_hw_process_cmd(void *hw_priv,
|
||||
*client_handle);
|
||||
break;
|
||||
}
|
||||
case CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE: {
|
||||
struct cam_cpas_hw_cmd_csid_input_core_info_update *core_info_update;
|
||||
|
||||
if (sizeof(struct cam_cpas_hw_cmd_csid_input_core_info_update) != arg_size) {
|
||||
CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", cmd_type, arg_size);
|
||||
break;
|
||||
}
|
||||
|
||||
core_info_update = (struct cam_cpas_hw_cmd_csid_input_core_info_update *)cmd_args;
|
||||
rc = cam_cpas_hw_csid_input_core_info_update(hw_priv, core_info_update->csid_idx,
|
||||
core_info_update->sfe_idx, core_info_update->set_port);
|
||||
break;
|
||||
}
|
||||
case CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME: {
|
||||
uint32_t *csid_idx;
|
||||
|
||||
if (sizeof(uint32_t) != arg_size) {
|
||||
CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
|
||||
cmd_type, arg_size);
|
||||
break;
|
||||
}
|
||||
|
||||
csid_idx = (uint32_t *)cmd_args;
|
||||
rc = cam_cpas_hw_csid_process_resume(hw_priv, *csid_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type);
|
||||
break;
|
||||
@@ -2963,6 +3332,9 @@ static int cam_cpas_util_create_debugfs(struct cam_cpas *cpas_core)
|
||||
|
||||
debugfs_create_bool("smart_qos_dump", 0644,
|
||||
cpas_core->dentry, &cpas_core->smart_qos_dump);
|
||||
|
||||
debugfs_create_bool("force_hlos_drv", 0644,
|
||||
cpas_core->dentry, &cpas_core->force_hlos_drv);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#define CAM_CPAS_INFLIGHT_WORKS 5
|
||||
#define CAM_CPAS_MAX_CLIENTS 42
|
||||
#define CAM_CPAS_MAX_AXI_PORTS 6
|
||||
#define CAM_CPAS_MAX_DRV_PORTS 4
|
||||
#define CAM_CPAS_MAX_TREE_LEVELS 4
|
||||
#define CAM_CPAS_MAX_RT_WR_NIU_NODES 10
|
||||
#define CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT 32
|
||||
@@ -65,6 +66,66 @@ enum cam_cpas_access_type {
|
||||
CAM_REG_TYPE_READ_WRITE,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum cam_cpas_vote_type - Enum for cpas vote type
|
||||
*/
|
||||
enum cam_cpas_vote_type {
|
||||
CAM_CPAS_VOTE_TYPE_HLOS,
|
||||
CAM_CPAS_VOTE_TYPE_DRV,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
|
||||
*
|
||||
* @vdd_corner : Voltage corner value
|
||||
* @ahb_level : AHB vote level corresponds to this vdd_corner
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_vdd_ahb_mapping {
|
||||
unsigned int vdd_corner;
|
||||
enum cam_vote_level ahb_level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_bw_vote : AXI bw vote
|
||||
*
|
||||
* @ab: AB bw value
|
||||
* @ib: IB bw value
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_bw_vote {
|
||||
uint64_t ab;
|
||||
uint64_t ib;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_drv_vote : DRV bw vote
|
||||
*
|
||||
* @high: Active bw values
|
||||
* @low: Sleep bw values
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_drv_vote {
|
||||
struct cam_cpas_bw_vote high;
|
||||
struct cam_cpas_bw_vote low;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_axi_bw_info : AXI bw info
|
||||
*
|
||||
* @vote_type: HLOS or DRV vote type
|
||||
* @hlos_vote: HLOS bw values
|
||||
* @drv_vote: DRV bw values
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_axi_bw_info {
|
||||
enum cam_cpas_vote_type vote_type;
|
||||
union {
|
||||
struct cam_cpas_bw_vote hlos_vote;
|
||||
struct cam_cpas_drv_vote drv_vote;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_internal_ops - CPAS Hardware layer internal ops
|
||||
*
|
||||
@@ -124,6 +185,7 @@ struct cam_cpas_reg {
|
||||
* @registered: Whether client has registered with cpas
|
||||
* @started: Whether client has streamed on
|
||||
* @tree_node_valid: Indicates whether tree node has at least one valid node
|
||||
* @is_drv_dyn: Indicates whether this client is DRV dynamic voting client
|
||||
* @ahb_level: Determined/Applied ahb level for the client
|
||||
* @axi_vote: Determined/Applied axi vote for the client
|
||||
* @axi_port: Client's parent axi port
|
||||
@@ -135,6 +197,7 @@ struct cam_cpas_client {
|
||||
bool registered;
|
||||
bool started;
|
||||
bool tree_node_valid;
|
||||
bool is_drv_dyn;
|
||||
enum cam_vote_level ahb_level;
|
||||
struct cam_axi_vote axi_vote;
|
||||
struct cam_cpas_axi_port *axi_port;
|
||||
@@ -168,12 +231,13 @@ struct cam_cpas_bus_client {
|
||||
* @ib_bw_voting_needed: if this port can update ib bw dynamically
|
||||
* @is_rt: if this port represents a real time axi port
|
||||
* @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
|
||||
* @drv_idx: DRV index for axi port node
|
||||
* @cam_rsc_dev: Cam RSC device for DRV
|
||||
* @is_drv_started: Indicates if DRV started for RSC device corresponding to port
|
||||
* @curr_bw: Current voted bw after cpas consolidation
|
||||
* @camnoc_bw: CAMNOC bw value for this port
|
||||
* @additional_bw: Additional bandwidth to cover non-hw cpas clients
|
||||
* @applied_ab_bw: applied ab bw for this port
|
||||
* @applied_ib_bw: applied ib bw for this port
|
||||
* @applied_bw: Actual applied bw to port
|
||||
*/
|
||||
struct cam_cpas_axi_port {
|
||||
const char *axi_port_name;
|
||||
@@ -181,31 +245,30 @@ struct cam_cpas_axi_port {
|
||||
bool ib_bw_voting_needed;
|
||||
bool is_rt;
|
||||
struct device_node *axi_port_node;
|
||||
uint64_t ab_bw;
|
||||
uint64_t ib_bw;
|
||||
uint32_t drv_idx;
|
||||
const struct device *cam_rsc_dev;
|
||||
bool is_drv_started;
|
||||
struct cam_cpas_axi_bw_info curr_bw;
|
||||
uint64_t camnoc_bw;
|
||||
uint64_t additional_bw;
|
||||
uint64_t applied_ab_bw;
|
||||
uint64_t applied_ib_bw;
|
||||
struct cam_cpas_axi_bw_info applied_bw;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_axi_port_debug_info : AXI port information
|
||||
*
|
||||
* @axi_port_name: Name of this AXI port
|
||||
* @ab_bw: AB bw value for this port
|
||||
* @ib_bw: IB bw value for this port
|
||||
* @curr_bw: Current voted bw after cpas consolidation
|
||||
* @camnoc_bw: CAMNOC bw value for this port
|
||||
* @applied_ab_bw: applied ab bw for this port
|
||||
* @applied_ib_bw: applied ib bw for this port
|
||||
* @applied_bw: Actual applied bw to port
|
||||
* @is_drv_started: Indicates if DRV started for RSC device corresponding to port
|
||||
*/
|
||||
struct cam_cpas_axi_port_debug_info {
|
||||
const char *axi_port_name;
|
||||
uint64_t ab_bw;
|
||||
uint64_t ib_bw;
|
||||
struct cam_cpas_axi_bw_info curr_bw;
|
||||
uint64_t camnoc_bw;
|
||||
uint64_t applied_ab_bw;
|
||||
uint64_t applied_ib_bw;
|
||||
struct cam_cpas_axi_bw_info applied_bw;
|
||||
bool is_drv_started;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -285,6 +348,7 @@ struct cam_cpas_monitor {
|
||||
* @slave_err_irq_en: Whether slave error irq is enabled to detect memory
|
||||
* config issues
|
||||
* @smmu_fault_handled: Handled address decode error, on fault at SMMU
|
||||
* @force_hlos_drv: Whether to force disable DRV voting
|
||||
*/
|
||||
struct cam_cpas {
|
||||
struct cam_cpas_hw_caps hw_caps;
|
||||
@@ -315,6 +379,7 @@ struct cam_cpas {
|
||||
bool smart_qos_dump;
|
||||
bool slave_err_irq_en;
|
||||
bool smmu_fault_handled;
|
||||
bool force_hlos_drv;
|
||||
};
|
||||
|
||||
int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CAM_CPAS_HW_INTF_H_
|
||||
@@ -47,9 +48,26 @@ enum cam_cpas_hw_cmd_process {
|
||||
CAM_CPAS_HW_CMD_ACTIVATE_LLC,
|
||||
CAM_CPAS_HW_CMD_DEACTIVATE_LLC,
|
||||
CAM_CPAS_HW_CMD_DUMP_BUFF_FILL_INFO,
|
||||
CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE,
|
||||
CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME,
|
||||
CAM_CPAS_HW_CMD_INVALID,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_hw_cmd_csid_input_core_info_update : CPAS cmd struct for updating acquired
|
||||
* csid core info to cpas
|
||||
*
|
||||
* @csid_idx: CSID core index
|
||||
* @sfe_idx: SFE core index corresponding to CSID core
|
||||
* @set_port: Indicates whether to set or reset port for given client
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_hw_cmd_csid_input_core_info_update {
|
||||
int csid_idx;
|
||||
int sfe_idx;
|
||||
bool set_port;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_cpas_hw_cmd_reg_read_write : CPAS cmd struct for reg read, write
|
||||
*
|
||||
|
@@ -144,6 +144,100 @@ const char *cam_cpas_axi_util_trans_type_to_string(
|
||||
}
|
||||
EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
|
||||
|
||||
const char *cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
uint32_t vote_lvl)
|
||||
{
|
||||
switch (vote_lvl) {
|
||||
case CAM_CPAS_VOTE_LEVEL_LOW:
|
||||
return "VOTE_LVL_LOW";
|
||||
case CAM_CPAS_VOTE_LEVEL_HIGH:
|
||||
return "VOTE_LVL_HIGH";
|
||||
default:
|
||||
return "VOTE_LVL_INVALID";
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(cam_cpas_axi_util_drv_vote_lvl_to_string);
|
||||
|
||||
int cam_cpas_query_drv_enable(bool *is_drv_enabled)
|
||||
{
|
||||
struct cam_hw_info *cpas_hw = NULL;
|
||||
struct cam_cpas_private_soc *soc_private = NULL;
|
||||
|
||||
if (!CAM_CPAS_INTF_INITIALIZED()) {
|
||||
CAM_ERR(CAM_CPAS, "cpas intf not initialized");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!is_drv_enabled) {
|
||||
CAM_ERR(CAM_CPAS, "invalid input %pK", is_drv_enabled);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
|
||||
soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
|
||||
|
||||
*is_drv_enabled = soc_private->enable_cam_ddr_drv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cam_cpas_query_drv_enable);
|
||||
|
||||
int cam_cpas_csid_process_resume(uint32_t csid_idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!CAM_CPAS_INTF_INITIALIZED()) {
|
||||
CAM_ERR(CAM_CPAS, "cpas intf not initialized");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
|
||||
rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
|
||||
g_cpas_intf->hw_intf->hw_priv,
|
||||
CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME, &csid_idx,
|
||||
sizeof(uint32_t));
|
||||
if (rc)
|
||||
CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
|
||||
} else {
|
||||
CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cam_cpas_csid_process_resume);
|
||||
|
||||
|
||||
int cam_cpas_csid_input_core_info_update(int csid_idx, int sfe_idx, bool set_port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!CAM_CPAS_INTF_INITIALIZED()) {
|
||||
CAM_ERR(CAM_CPAS, "cpas intf not initialized");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
|
||||
struct cam_cpas_hw_cmd_csid_input_core_info_update core_info_update;
|
||||
|
||||
core_info_update.csid_idx = csid_idx;
|
||||
core_info_update.sfe_idx = sfe_idx;
|
||||
core_info_update.set_port = set_port;
|
||||
rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
|
||||
g_cpas_intf->hw_intf->hw_priv,
|
||||
CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE, &core_info_update,
|
||||
sizeof(core_info_update));
|
||||
if (rc)
|
||||
CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
|
||||
} else {
|
||||
CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cam_cpas_csid_input_core_info_update);
|
||||
|
||||
int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle)
|
||||
{
|
||||
int rc;
|
||||
|
@@ -17,8 +17,9 @@
|
||||
#include "cam_cpas_hw_intf.h"
|
||||
#include "cam_cpas_hw.h"
|
||||
#include "cam_cpas_soc.h"
|
||||
#include "cam_compat.h"
|
||||
|
||||
static uint cpas_dump;
|
||||
static uint cpas_dump = 1;
|
||||
module_param(cpas_dump, uint, 0644);
|
||||
|
||||
#define CAM_ICP_CLK_NAME "cam_icp_clk"
|
||||
@@ -42,11 +43,12 @@ void cam_cpas_dump_axi_vote_info(
|
||||
|
||||
for (i = 0; i < axi_vote->num_paths; i++) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"Client [%s][%d] : [%s], Path=[%d] [%d], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]",
|
||||
"Client [%s][%d] : [%s], Path=[%d] [%d], [%s], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]",
|
||||
cpas_client->data.identifier, cpas_client->data.cell_index,
|
||||
identifier,
|
||||
axi_vote->axi_path[i].path_data_type,
|
||||
axi_vote->axi_path[i].transac_type,
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(axi_vote->axi_path[i].vote_level),
|
||||
axi_vote->axi_path[i].camnoc_bw,
|
||||
axi_vote->axi_path[i].mnoc_ab_bw,
|
||||
axi_vote->axi_path[i].mnoc_ib_bw);
|
||||
@@ -71,7 +73,7 @@ void cam_cpas_util_debug_parse_data(
|
||||
CAM_INFO(CAM_CPAS,
|
||||
"NODE cell_idx: %d, level: %d, name: %s, axi_port_idx: %d, merge_type: %d, parent_name: %s camnoc_max_needed: %d",
|
||||
curr_node->cell_idx, curr_node->level_idx,
|
||||
curr_node->node_name, curr_node->axi_port_idx,
|
||||
curr_node->node_name, curr_node->axi_port_idx_arr[CAM_CPAS_PORT_HLOS_DRV],
|
||||
curr_node->merge_type, curr_node->parent_node ?
|
||||
curr_node->parent_node->node_name : "no parent",
|
||||
curr_node->camnoc_max_needed);
|
||||
@@ -79,10 +81,10 @@ void cam_cpas_util_debug_parse_data(
|
||||
if (curr_node->level_idx)
|
||||
continue;
|
||||
|
||||
CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s",
|
||||
CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s drv_voting_idx:%d",
|
||||
curr_node->path_data_type,
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
curr_node->path_trans_type));
|
||||
curr_node->path_trans_type), curr_node->drv_voting_idx);
|
||||
|
||||
for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) {
|
||||
CAM_INFO(CAM_CPAS, "Constituent path: %d",
|
||||
@@ -100,6 +102,10 @@ int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core,
|
||||
|
||||
for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) {
|
||||
if (soc_private->tree_node[i]) {
|
||||
kfree(soc_private->tree_node[i]->bw_info);
|
||||
kfree(soc_private->tree_node[i]->axi_port_idx_arr);
|
||||
soc_private->tree_node[i]->bw_info = NULL;
|
||||
soc_private->tree_node[i]->axi_port_idx_arr = NULL;
|
||||
of_node_put(soc_private->tree_node[i]->tree_dev_node);
|
||||
kfree(soc_private->tree_node[i]);
|
||||
soc_private->tree_node[i] = NULL;
|
||||
@@ -182,6 +188,151 @@ static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_cpas_parse_mnoc_node(struct cam_cpas *cpas_core,
|
||||
struct cam_cpas_private_soc *soc_private, struct cam_cpas_tree_node *curr_node_ptr,
|
||||
struct device_node *mnoc_node, int *mnoc_idx)
|
||||
{
|
||||
int rc = 0, count = 0, i;
|
||||
bool ib_voting_needed = false, is_rt_port = false;
|
||||
struct of_phandle_args src_args = {0}, dst_args = {0};
|
||||
|
||||
ib_voting_needed = of_property_read_bool(curr_node_ptr->tree_dev_node,
|
||||
"ib-bw-voting-needed");
|
||||
is_rt_port = of_property_read_bool(curr_node_ptr->tree_dev_node, "rt-axi-port");
|
||||
|
||||
if (soc_private->bus_icc_based) {
|
||||
count = of_property_count_strings(mnoc_node, "interconnect-names");
|
||||
if (count <= 0) {
|
||||
CAM_ERR(CAM_CPAS, "no interconnect-names found");
|
||||
count = 0;
|
||||
return -EINVAL;
|
||||
} else if (count > CAM_CPAS_MAX_DRV_PORTS) {
|
||||
CAM_ERR(CAM_CPAS, "Number of interconnects %d greater than max ports %d",
|
||||
count, CAM_CPAS_MAX_DRV_PORTS);
|
||||
count = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((i > 0) && !soc_private->enable_cam_ddr_drv)
|
||||
break;
|
||||
|
||||
if (*mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid mnoc index: %d", *mnoc_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpas_core->axi_port[*mnoc_idx].axi_port_node = mnoc_node;
|
||||
rc = of_property_read_string_index(mnoc_node, "interconnect-names", i,
|
||||
&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", (2 * i), &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", ((2 * i) + 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;
|
||||
cpas_core->axi_port[*mnoc_idx].axi_port_name =
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name;
|
||||
cpas_core->axi_port[*mnoc_idx].drv_idx = i;
|
||||
|
||||
if (i > CAM_CPAS_PORT_HLOS_DRV) {
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.is_drv_port =
|
||||
true;
|
||||
cpas_core->axi_port[*mnoc_idx].curr_bw.vote_type =
|
||||
CAM_CPAS_VOTE_TYPE_DRV;
|
||||
cpas_core->axi_port[*mnoc_idx].applied_bw.vote_type =
|
||||
CAM_CPAS_VOTE_TYPE_DRV;
|
||||
cpas_core->axi_port[*mnoc_idx].cam_rsc_dev =
|
||||
cam_cpas_get_rsc_dev_for_drv(i - CAM_CPAS_PORT_DRV_0);
|
||||
if (!cpas_core->axi_port[*mnoc_idx].cam_rsc_dev) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Port[%s][%d] Failed to get rsc device drv_idx:%d",
|
||||
cpas_core->axi_port[*mnoc_idx].axi_port_name,
|
||||
*mnoc_idx, i);
|
||||
rc = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The indexes of axi_port_idx_arr map to drv_voting_idx,
|
||||
* with 0 pointing to hlos drv bus ID
|
||||
*/
|
||||
curr_node_ptr->axi_port_idx_arr[i] = *mnoc_idx;
|
||||
cpas_core->axi_port[*mnoc_idx].ib_bw_voting_needed = ib_voting_needed;
|
||||
cpas_core->axi_port[*mnoc_idx].is_rt = is_rt_port;
|
||||
CAM_DBG(CAM_PERF, "Adding Bus Client=[%s] : src=%d, dst=%d mnoc_idx:%d",
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name,
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.src_id,
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.dst_id,
|
||||
*mnoc_idx);
|
||||
(*mnoc_idx)++;
|
||||
cpas_core->num_axi_ports++;
|
||||
}
|
||||
} else {
|
||||
if (soc_private->enable_cam_ddr_drv) {
|
||||
CAM_ERR(CAM_CPAS, "DRV not supported for old bus scaling clients");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
cpas_core->axi_port[*mnoc_idx].axi_port_node = mnoc_node;
|
||||
rc = of_property_read_string(curr_node_ptr->tree_dev_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].axi_port_name =
|
||||
cpas_core->axi_port[*mnoc_idx].bus_client.common_data.name;
|
||||
curr_node_ptr->axi_port_idx_arr[0] = *mnoc_idx;
|
||||
cpas_core->axi_port[*mnoc_idx].ib_bw_voting_needed = ib_voting_needed;
|
||||
cpas_core->axi_port[*mnoc_idx].is_rt = is_rt_port;
|
||||
(*mnoc_idx)++;
|
||||
cpas_core->num_axi_ports++;
|
||||
}
|
||||
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
struct device_node *of_node, struct cam_cpas_private_soc *soc_private)
|
||||
{
|
||||
@@ -198,7 +349,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
const char *client_name = NULL;
|
||||
uint32_t client_idx = 0, cell_idx = 0;
|
||||
uint8_t niu_idx = 0;
|
||||
int rc = 0, count = 0, i;
|
||||
int rc = 0, count = 0, i, j, num_drv_ports;
|
||||
|
||||
camera_bus_node = of_get_child_by_name(of_node, "camera-bus-nodes");
|
||||
if (!camera_bus_node) {
|
||||
@@ -209,8 +360,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
soc_private->camera_bus_node = camera_bus_node;
|
||||
|
||||
for_each_available_child_of_node(camera_bus_node, level_node) {
|
||||
rc = of_property_read_u32(level_node, "level-index",
|
||||
&level_idx);
|
||||
rc = of_property_read_u32(level_node, "level-index", &level_idx);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Error reading level idx rc: %d", rc);
|
||||
return rc;
|
||||
@@ -226,6 +376,11 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
if (soc_private->enable_smart_qos)
|
||||
soc_private->smart_qos_info->num_rt_wr_nius = 0;
|
||||
|
||||
if (soc_private->enable_cam_ddr_drv)
|
||||
num_drv_ports = CAM_CPAS_MAX_DRV_PORTS;
|
||||
else
|
||||
num_drv_ports = 1;
|
||||
|
||||
for (level_idx = (CAM_CPAS_MAX_TREE_LEVELS - 1); level_idx >= 0;
|
||||
level_idx--) {
|
||||
level_node = soc_private->level_node[level_idx];
|
||||
@@ -234,12 +389,9 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
|
||||
CAM_DBG(CAM_CPAS, "Parsing level %d nodes", level_idx);
|
||||
|
||||
camnoc_max_needed = of_property_read_bool(level_node,
|
||||
"camnoc-max-needed");
|
||||
camnoc_max_needed = of_property_read_bool(level_node, "camnoc-max-needed");
|
||||
for_each_available_child_of_node(level_node, curr_node) {
|
||||
curr_node_ptr =
|
||||
kzalloc(sizeof(struct cam_cpas_tree_node),
|
||||
GFP_KERNEL);
|
||||
curr_node_ptr = kzalloc(sizeof(struct cam_cpas_tree_node), GFP_KERNEL);
|
||||
if (!curr_node_ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -256,50 +408,54 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
|
||||
if (curr_node_ptr->cell_idx >=
|
||||
CAM_CPAS_MAX_TREE_NODES) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid cell idx: %d",
|
||||
curr_node_ptr->cell_idx);
|
||||
CAM_ERR(CAM_CPAS, "Invalid cell idx: %d", curr_node_ptr->cell_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
soc_private->tree_node[curr_node_ptr->cell_idx] =
|
||||
curr_node_ptr;
|
||||
soc_private->tree_node[curr_node_ptr->cell_idx] = curr_node_ptr;
|
||||
curr_node_ptr->level_idx = level_idx;
|
||||
|
||||
rc = of_property_read_string(curr_node, "node-name",
|
||||
&curr_node_ptr->node_name);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"failed to read node-name rc=%d",
|
||||
rc);
|
||||
CAM_ERR(CAM_CPAS, "failed to read node-name rc=%d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos &&
|
||||
(level_idx == 1) &&
|
||||
curr_node_ptr->bw_info = kzalloc((sizeof(struct cam_cpas_axi_bw_info) *
|
||||
num_drv_ports), GFP_KERNEL);
|
||||
if (!curr_node_ptr->bw_info) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in allocating memory for bw info");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
curr_node_ptr->axi_port_idx_arr = kzalloc((sizeof(int) * num_drv_ports),
|
||||
GFP_KERNEL);
|
||||
if (!curr_node_ptr->axi_port_idx_arr) {
|
||||
CAM_ERR(CAM_CPAS, "Failed in allocating memory for port indices");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (soc_private->enable_smart_qos && (level_idx == 1) &&
|
||||
of_property_read_bool(curr_node, "rt-wr-niu")) {
|
||||
|
||||
rc = of_property_read_u32(curr_node,
|
||||
"priority-lut-low-offset",
|
||||
rc = of_property_read_u32(curr_node, "priority-lut-low-offset",
|
||||
&curr_node_ptr->pri_lut_low_offset);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid priority offset rc %d",
|
||||
rc);
|
||||
CAM_ERR(CAM_CPAS, "Invalid priority offset rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(curr_node, "niu-size",
|
||||
&curr_node_ptr->niu_size);
|
||||
if (rc || !curr_node_ptr->niu_size) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid niu size rc %d", rc);
|
||||
CAM_ERR(CAM_CPAS, "Invalid niu size rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
niu_idx = soc_private->smart_qos_info->num_rt_wr_nius;
|
||||
if (niu_idx >= CAM_CPAS_MAX_RT_WR_NIU_NODES) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid number of level1 nodes %d",
|
||||
CAM_ERR(CAM_CPAS, "Invalid number of level1 nodes %d",
|
||||
soc_private->smart_qos_info->num_rt_wr_nius);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -310,8 +466,7 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"level1[%d] : Node %s idx %d priority offset 0x%x, NIU size %dKB",
|
||||
niu_idx,
|
||||
curr_node_ptr->node_name, curr_node_ptr->cell_idx,
|
||||
niu_idx, curr_node_ptr->node_name, curr_node_ptr->cell_idx,
|
||||
curr_node_ptr->pri_lut_low_offset, curr_node_ptr->niu_size);
|
||||
}
|
||||
|
||||
@@ -321,187 +476,83 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
if (rc)
|
||||
curr_node_ptr->bus_width_factor = 1;
|
||||
|
||||
rc = of_property_read_u32(curr_node,
|
||||
"traffic-merge-type",
|
||||
rc = of_property_read_u32(curr_node, "traffic-merge-type",
|
||||
&curr_node_ptr->merge_type);
|
||||
|
||||
curr_node_ptr->axi_port_idx = -1;
|
||||
mnoc_node = of_get_child_by_name(curr_node,
|
||||
"qcom,axi-port-mnoc");
|
||||
for (j = 0; j < num_drv_ports; j++)
|
||||
curr_node_ptr->axi_port_idx_arr[j] = -1;
|
||||
|
||||
mnoc_node = of_get_child_by_name(curr_node, "qcom,axi-port-mnoc");
|
||||
if (mnoc_node) {
|
||||
if (mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid mnoc index: %d",
|
||||
mnoc_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpas_core->axi_port[mnoc_idx].axi_port_node
|
||||
= mnoc_node;
|
||||
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);
|
||||
rc = cam_cpas_parse_mnoc_node(cpas_core, soc_private, curr_node_ptr,
|
||||
mnoc_node, &mnoc_idx);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"failed to read interconnect-names rc=%d",
|
||||
CAM_ERR(CAM_CPAS, "failed to parse mnoc node info 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].axi_port_name =
|
||||
cpas_core->axi_port[mnoc_idx]
|
||||
.bus_client.common_data.name;
|
||||
cpas_core->axi_port
|
||||
[mnoc_idx].ib_bw_voting_needed
|
||||
= of_property_read_bool(curr_node,
|
||||
"ib-bw-voting-needed");
|
||||
cpas_core->axi_port
|
||||
[mnoc_idx].is_rt
|
||||
= of_property_read_bool(curr_node,
|
||||
"rt-axi-port");
|
||||
curr_node_ptr->axi_port_idx = mnoc_idx;
|
||||
mnoc_idx++;
|
||||
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);
|
||||
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");
|
||||
CAM_ERR(CAM_CPAS, "failed to parse camnoc node info rc=%d",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = of_property_read_string(curr_node,
|
||||
"client-name", &client_name);
|
||||
rc = of_property_read_string(curr_node, "client-name", &client_name);
|
||||
if (!rc) {
|
||||
rc = of_property_read_u32(curr_node,
|
||||
"traffic-data", &curr_node_ptr->path_data_type);
|
||||
rc = of_property_read_u32(curr_node, "traffic-data",
|
||||
&curr_node_ptr->path_data_type);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Path Data type not found");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cam_cpas_util_path_type_to_idx(
|
||||
&curr_node_ptr->path_data_type);
|
||||
rc = cam_cpas_util_path_type_to_idx(&curr_node_ptr->path_data_type);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Incorrect path type for client: %s",
|
||||
client_name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(curr_node,
|
||||
"traffic-transaction-type",
|
||||
rc = of_property_read_u32(curr_node, "traffic-transaction-type",
|
||||
&curr_node_ptr->path_trans_type);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Path Transac type not found");
|
||||
CAM_ERR(CAM_CPAS, "Path Transac type not found");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (curr_node_ptr->path_trans_type >=
|
||||
CAM_CPAS_TRANSACTION_MAX) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid transac type: %d",
|
||||
if (curr_node_ptr->path_trans_type >= CAM_CPAS_TRANSACTION_MAX) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid transac type: %d",
|
||||
curr_node_ptr->path_trans_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
count = of_property_count_u32_elems(curr_node,
|
||||
"constituent-paths");
|
||||
count = of_property_count_u32_elems(curr_node, "constituent-paths");
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = of_property_read_u32_index(
|
||||
curr_node, "constituent-paths",
|
||||
i, &path_idx);
|
||||
rc = of_property_read_u32_index(curr_node,
|
||||
"constituent-paths", i, &path_idx);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"No constituent path at %d", i);
|
||||
CAM_ERR(CAM_CPAS, "No constituent path at %d", i);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cam_cpas_util_path_type_to_idx(
|
||||
&path_idx);
|
||||
rc = cam_cpas_util_path_type_to_idx(&path_idx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
curr_node_ptr->constituent_paths
|
||||
[path_idx] = true;
|
||||
curr_node_ptr->constituent_paths[path_idx] = true;
|
||||
}
|
||||
|
||||
rc = cam_common_util_get_string_index(
|
||||
soc_private->client_name,
|
||||
soc_private->num_clients,
|
||||
client_name, &client_idx);
|
||||
rc = cam_common_util_get_string_index(soc_private->client_name,
|
||||
soc_private->num_clients, client_name, &client_idx);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"client name not found in list: %s",
|
||||
CAM_ERR(CAM_CPAS, "client name not found in list: %s",
|
||||
client_name);
|
||||
return rc;
|
||||
}
|
||||
@@ -509,33 +560,46 @@ static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core,
|
||||
if (client_idx >= CAM_CPAS_MAX_CLIENTS)
|
||||
return -EINVAL;
|
||||
|
||||
curr_client =
|
||||
cpas_core->cpas_client[client_idx];
|
||||
curr_client = cpas_core->cpas_client[client_idx];
|
||||
curr_client->tree_node_valid = true;
|
||||
curr_client->tree_node
|
||||
[curr_node_ptr->path_data_type]
|
||||
[curr_node_ptr->path_trans_type] =
|
||||
curr_node_ptr;
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"CLIENT NODE ADDED: %d %d %s",
|
||||
curr_node_ptr->path_data_type,
|
||||
curr_node_ptr->path_trans_type,
|
||||
client_name);
|
||||
curr_client->tree_node[curr_node_ptr->path_data_type]
|
||||
[curr_node_ptr->path_trans_type] = curr_node_ptr;
|
||||
|
||||
if (soc_private->enable_cam_ddr_drv) {
|
||||
rc = of_property_read_u32(curr_node, "drv-voting-index",
|
||||
&curr_node_ptr->drv_voting_idx);
|
||||
if (curr_node_ptr->drv_voting_idx == CAM_CPAS_PORT_DRV_DYN)
|
||||
curr_client->is_drv_dyn = true;
|
||||
|
||||
if (curr_client->is_drv_dyn &&
|
||||
(curr_node_ptr->drv_voting_idx !=
|
||||
CAM_CPAS_PORT_DRV_DYN))
|
||||
CAM_ERR(CAM_CPAS,
|
||||
"Invalid config for drv dyn client: %s drv_idx: %d",
|
||||
client_name, curr_node_ptr->drv_voting_idx);
|
||||
}
|
||||
|
||||
parent_node = of_parse_phandle(curr_node,
|
||||
"parent-node", 0);
|
||||
CAM_DBG(CAM_CPAS, "Client Node Added: %d %d %s %d",
|
||||
curr_node_ptr->path_data_type,
|
||||
curr_node_ptr->path_trans_type, client_name,
|
||||
curr_node_ptr->drv_voting_idx);
|
||||
}
|
||||
|
||||
if (soc_private->enable_cam_ddr_drv)
|
||||
for (j = CAM_CPAS_PORT_DRV_0; j < num_drv_ports; j++)
|
||||
curr_node_ptr->bw_info[j].vote_type =
|
||||
CAM_CPAS_VOTE_TYPE_DRV;
|
||||
|
||||
parent_node = of_parse_phandle(curr_node, "parent-node", 0);
|
||||
if (parent_node) {
|
||||
of_property_read_u32(parent_node, "cell-index",
|
||||
&cell_idx);
|
||||
curr_node_ptr->parent_node =
|
||||
soc_private->tree_node[cell_idx];
|
||||
of_property_read_u32(parent_node, "cell-index", &cell_idx);
|
||||
curr_node_ptr->parent_node = soc_private->tree_node[cell_idx];
|
||||
} else {
|
||||
CAM_DBG(CAM_CPAS,
|
||||
"no parent node at this level");
|
||||
CAM_DBG(CAM_CPAS, "no parent node at this level");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_init(&cpas_core->tree_lock);
|
||||
cam_cpas_util_debug_parse_data(soc_private);
|
||||
|
||||
@@ -807,6 +871,7 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
|
||||
struct device_node *of_node;
|
||||
struct of_phandle_args src_args = {0}, dst_args = {0};
|
||||
int count = 0, i = 0, rc = 0, num_bw_values = 0, num_levels = 0;
|
||||
uint32_t cam_drv_en_mask_val = 0;
|
||||
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
|
||||
|
||||
if (!soc_private || !pdev) {
|
||||
@@ -1120,6 +1185,10 @@ int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw,
|
||||
soc_private->smart_qos_info = NULL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(of_node, "enable-cam-drv", &cam_drv_en_mask_val);
|
||||
if (cam_drv_en_mask_val & CAM_DDR_DRV)
|
||||
soc_private->enable_cam_ddr_drv = true;
|
||||
|
||||
rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc);
|
||||
|
@@ -15,34 +15,21 @@
|
||||
#define CAM_CPAS_MAX_TREE_NODES 61
|
||||
#define CAM_CPAS_MAX_FUSE_FEATURE 10
|
||||
|
||||
/**
|
||||
* struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping
|
||||
*
|
||||
* @vdd_corner : Voltage corner value
|
||||
* @ahb_level : AHB vote level corresponds to this vdd_corner
|
||||
*
|
||||
*/
|
||||
struct cam_cpas_vdd_ahb_mapping {
|
||||
unsigned int vdd_corner;
|
||||
enum cam_vote_level ahb_level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cpas_tree_node: Generic cpas tree node for BW voting
|
||||
*
|
||||
* @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
|
||||
* @axi_port_idx_arr: Index to identify which axi port to vote the consolidated bw.
|
||||
* It can point to multiple indexes in case of camera DRV
|
||||
* @drv_voting_idx: Specifies the index to which the child node would finally vote.
|
||||
* @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
|
||||
* @bus_width_factor: Factor for accounting bus width in CAMNOC bw calculation
|
||||
* @camnoc_bw: CAMNOC bw value at current node
|
||||
* @mnoc_ab_bw: MNOC AB bw value at current node
|
||||
* @mnoc_ib_bw: MNOC IB bw value at current node
|
||||
* @ddr_ab_bw: DDR AB bw value at current node
|
||||
* @ddr_ib_bw: DDR IB bw value at current node
|
||||
* @bw_info: AXI BW info for all drv ports
|
||||
* @camnoc_max_needed: If node is needed for CAMNOC BW calculation then true
|
||||
* @constituent_paths: Constituent paths presence info from device tree
|
||||
* Ex: For CAM_CPAS_PATH_DATA_IFE_UBWC_STATS, index corresponding to
|
||||
@@ -61,7 +48,8 @@ struct cam_cpas_vdd_ahb_mapping {
|
||||
struct cam_cpas_tree_node {
|
||||
uint32_t cell_idx;
|
||||
int level_idx;
|
||||
int axi_port_idx;
|
||||
int *axi_port_idx_arr;
|
||||
int drv_voting_idx;
|
||||
int camnoc_axi_port_idx;
|
||||
const char *node_name;
|
||||
uint32_t path_data_type;
|
||||
@@ -69,10 +57,7 @@ struct cam_cpas_tree_node {
|
||||
uint32_t merge_type;
|
||||
uint32_t bus_width_factor;
|
||||
uint64_t camnoc_bw;
|
||||
uint64_t mnoc_ab_bw;
|
||||
uint64_t mnoc_ib_bw;
|
||||
uint64_t ddr_ab_bw;
|
||||
uint64_t ddr_ib_bw;
|
||||
struct cam_cpas_axi_bw_info *bw_info;
|
||||
bool camnoc_max_needed;
|
||||
bool constituent_paths[CAM_CPAS_PATH_DATA_MAX];
|
||||
struct device_node *tree_dev_node;
|
||||
@@ -163,6 +148,7 @@ struct cam_cpas_smart_qos_info {
|
||||
* @num_caches: Number of last level caches
|
||||
* @llcc_info: Cache info
|
||||
* @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset
|
||||
* @enable_cam_ddr_drv: Whether to enable Camera DDR DRV on current chipset
|
||||
* @smart_qos_info: Pointer to smart qos info
|
||||
* @icp_clk_index: Index of optional icp clk
|
||||
*/
|
||||
@@ -188,6 +174,7 @@ struct cam_cpas_private_soc {
|
||||
uint32_t num_caches;
|
||||
struct cam_sys_cache_info *llcc_info;
|
||||
bool enable_smart_qos;
|
||||
bool enable_cam_ddr_drv;
|
||||
struct cam_cpas_smart_qos_info *smart_qos_info;
|
||||
int32_t icp_clk_index;
|
||||
};
|
||||
|
@@ -750,6 +750,19 @@ const char *cam_cpas_axi_util_path_type_to_string(
|
||||
const char *cam_cpas_axi_util_trans_type_to_string(
|
||||
uint32_t path_data_type);
|
||||
|
||||
/**
|
||||
* cam_cpas_axi_util_drv_vote_lvl_to_string()
|
||||
*
|
||||
* @brief: API to get string for given DRV vote level
|
||||
*
|
||||
* @vote_lvl : DRV vote level
|
||||
*
|
||||
* @return string.
|
||||
*
|
||||
*/
|
||||
const char *cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
uint32_t vote_lvl);
|
||||
|
||||
/**
|
||||
* cam_cpas_log_votes()
|
||||
*
|
||||
@@ -838,4 +851,40 @@ int cam_cpas_deactivate_llcc(enum cam_sys_cache_config_types type);
|
||||
*/
|
||||
int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle);
|
||||
|
||||
/**
|
||||
* cam_cpas_csid_input_core_info_update()
|
||||
*
|
||||
* @brief: API to communicate csid input core info to cpas
|
||||
*
|
||||
* @csid_idx: csid hw index connected to particular sfe
|
||||
* @sfe_idx: sfe idx to be connected to particular DRV path
|
||||
* @set_port: Indicates whether to set or reset DRV port info in dynamic client
|
||||
*
|
||||
* @return 0 on success
|
||||
*
|
||||
*/
|
||||
int cam_cpas_csid_input_core_info_update(int csid_idx, int sfe_idx, bool set_port);
|
||||
|
||||
/**
|
||||
* cam_cpas_csid_process_resume()
|
||||
*
|
||||
* @brief: API to process csid resume in cpas
|
||||
* @csid_idx: CSID idx to notify resume for
|
||||
*
|
||||
* @return 0 on success
|
||||
*
|
||||
*/
|
||||
int cam_cpas_csid_process_resume(uint32_t csid_idx);
|
||||
|
||||
/**
|
||||
* cam_cpas_query_drv_enable()
|
||||
*
|
||||
* @brief: API to indicate DRV enabled on hw or not
|
||||
* @is_drv_enabled: Indication to be set by the API
|
||||
*
|
||||
* @return 0 on success
|
||||
*
|
||||
*/
|
||||
int cam_cpas_query_drv_enable(bool *is_drv_enabled);
|
||||
|
||||
#endif /* _CAM_CPAS_API_H_ */
|
||||
|
@@ -65,6 +65,9 @@ static struct cam_ife_hw_mgr g_ife_hw_mgr;
|
||||
static uint32_t g_num_ife, g_num_ife_lite, g_num_sfe;
|
||||
static uint32_t max_ife_out_res, max_sfe_out_res;
|
||||
|
||||
static int cam_ife_mgr_find_core_idx(int split_id, struct cam_ife_hw_mgr_ctx *ctx,
|
||||
enum cam_isp_hw_type hw_type, uint32_t *core_idx);
|
||||
|
||||
static int cam_isp_blob_ife_clock_update(
|
||||
struct cam_isp_clock_config *clock_config,
|
||||
struct cam_ife_hw_mgr_ctx *ctx);
|
||||
@@ -85,6 +88,88 @@ static int cam_ife_mgr_prog_default_settings(
|
||||
static int cam_ife_mgr_cmd_get_sof_timestamp(struct cam_ife_hw_mgr_ctx *ife_ctx,
|
||||
uint64_t *time_stamp, uint64_t *boot_time_stamp, uint64_t *prev_time_stamp);
|
||||
|
||||
static int cam_ife_mgr_update_core_info_to_cpas(struct cam_ife_hw_mgr_ctx *ctx,
|
||||
bool set_port)
|
||||
{
|
||||
struct cam_isp_hw_mgr_res *hw_mgr_res;
|
||||
int i, sfe_core_idx, csid_core_idx, rc = 0;
|
||||
|
||||
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
|
||||
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
|
||||
if (!hw_mgr_res->hw_res[i])
|
||||
continue;
|
||||
|
||||
rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_CSID,
|
||||
&csid_core_idx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_SFE, &sfe_core_idx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = cam_cpas_csid_input_core_info_update(csid_core_idx, sfe_core_idx,
|
||||
set_port);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_PERF, "Failed in updating core info to cpas rc: %d",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cam_isp_blob_drv_config(struct cam_ife_hw_mgr_ctx *ctx,
|
||||
uint64_t request_id, struct cam_isp_prepare_hw_update_data *prepare_hw_data)
|
||||
{
|
||||
struct cam_ife_hw_mgr *ife_hw_mgr;
|
||||
struct cam_hw_intf *hw_intf;
|
||||
struct cam_isp_drv_config *drv_config;
|
||||
struct cam_ife_csid_drv_config_args drv_config_args = {0};
|
||||
int i, rc = 0;
|
||||
|
||||
ife_hw_mgr = ctx->hw_mgr;
|
||||
drv_config = &prepare_hw_data->isp_drv_config;
|
||||
|
||||
CAM_DBG(CAM_PERF,
|
||||
"DRV config blob opcode:%u req_id:%llu disable_drv_override:%s ctx_idx:%u drv_en:%u path_idle_en:0x%x timeout_val:%u",
|
||||
prepare_hw_data->packet_opcode_type, request_id,
|
||||
CAM_BOOL_TO_YESNO(g_ife_hw_mgr.debug_cfg.disable_isp_drv),
|
||||
ctx->ctx_index, drv_config->drv_en, drv_config->path_idle_en,
|
||||
drv_config->timeout_val);
|
||||
|
||||
if (!g_ife_hw_mgr.cam_ddr_drv_support || g_ife_hw_mgr.debug_cfg.disable_isp_drv)
|
||||
return rc;
|
||||
|
||||
if (prepare_hw_data->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV)
|
||||
drv_config_args.is_init_config = true;
|
||||
|
||||
drv_config_args.drv_en = drv_config->drv_en;
|
||||
drv_config_args.path_idle_en = drv_config->path_idle_en;
|
||||
drv_config_args.timeout_val = drv_config->timeout_val;
|
||||
for (i = 0; i < ctx->num_base; i++) {
|
||||
if (ctx->base[i].hw_type != CAM_ISP_HW_TYPE_CSID)
|
||||
continue;
|
||||
|
||||
hw_intf = ife_hw_mgr->csid_devices[ctx->base[i].idx];
|
||||
if (hw_intf && hw_intf->hw_ops.process_cmd) {
|
||||
rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
|
||||
CAM_ISP_HW_CMD_DRV_CONFIG, &drv_config_args,
|
||||
sizeof(struct cam_ife_csid_drv_config_args));
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_PERF,
|
||||
"DRV config failed req_id:%d i:%d hw_idx=%d rc:%d",
|
||||
request_id, i, ctx->base[i].idx, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool cam_isp_is_ctx_primary_rdi(struct cam_ife_hw_mgr_ctx *ctx)
|
||||
{
|
||||
/* check for RDI only and RDI PD context*/
|
||||
@@ -1807,6 +1892,7 @@ static int cam_ife_mgr_process_base_info(
|
||||
res->hw_intf->hw_idx);
|
||||
}
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base);
|
||||
|
||||
return 0;
|
||||
@@ -5190,6 +5276,12 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
|
||||
goto free_res;
|
||||
}
|
||||
|
||||
if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
|
||||
rc = cam_ife_mgr_update_core_info_to_cpas(ife_ctx, true);
|
||||
if (rc)
|
||||
goto free_res;
|
||||
}
|
||||
|
||||
rc = cam_ife_mgr_allocate_cdm_cmd(
|
||||
(ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE ? true : false),
|
||||
&ife_ctx->cdm_cmd);
|
||||
@@ -5526,6 +5618,12 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
|
||||
goto free_res;
|
||||
}
|
||||
|
||||
if (ife_ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
|
||||
rc = cam_ife_mgr_update_core_info_to_cpas(ife_ctx, true);
|
||||
if (rc)
|
||||
goto free_res;
|
||||
}
|
||||
|
||||
rc = cam_ife_mgr_allocate_cdm_cmd(false,
|
||||
&ife_ctx->cdm_cmd);
|
||||
if (rc)
|
||||
@@ -5843,13 +5941,15 @@ static int cam_isp_classify_vote_info(
|
||||
|
||||
for (i = 0; i < isp_vote->num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"CLASSIFY_VOTE [%s] [%s] [%s] [%llu] [%llu] [%llu]",
|
||||
"CLASSIFY_VOTE [%s] [%s] [%s] [%s] [%llu] [%llu] [%llu]",
|
||||
cam_isp_util_usage_data_to_string(
|
||||
isp_vote->axi_path[i].usage_data),
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
isp_vote->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
isp_vote->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
isp_vote->axi_path[i].vote_level),
|
||||
isp_vote->axi_path[i].camnoc_bw,
|
||||
isp_vote->axi_path[i].mnoc_ab_bw,
|
||||
isp_vote->axi_path[i].mnoc_ib_bw);
|
||||
@@ -5873,7 +5973,7 @@ static int cam_isp_blob_bw_update_v2(
|
||||
|
||||
for (i = 0; i < bw_config->num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"ISP_BLOB usage_type=%u [%s] [%s] [%s] [%llu] [%llu] [%llu]",
|
||||
"ISP_BLOB usage_type=%u [%s] [%s] [%s] [%s] [%llu] [%llu] [%llu]",
|
||||
bw_config->usage_type,
|
||||
cam_isp_util_usage_data_to_string(
|
||||
bw_config->axi_path[i].usage_data),
|
||||
@@ -5881,6 +5981,8 @@ static int cam_isp_blob_bw_update_v2(
|
||||
bw_config->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
bw_config->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
bw_config->axi_path[i].vote_level),
|
||||
bw_config->axi_path[i].camnoc_bw,
|
||||
bw_config->axi_path[i].mnoc_ab_bw,
|
||||
bw_config->axi_path[i].mnoc_ib_bw);
|
||||
@@ -6167,6 +6269,14 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
|
||||
hw_update_data->bw_clk_config.ife_clock_config_valid,
|
||||
hw_update_data->bw_clk_config.sfe_clock_config_valid);
|
||||
|
||||
if (hw_update_data->drv_config_valid) {
|
||||
rc = cam_isp_blob_drv_config(ctx, cfg->request_id, hw_update_data);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_ISP, "DRV config failed for req: %llu rc:%d", cfg->request_id,
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update clock and bw values to top layer, the actual application of these
|
||||
* votes to hw will happen for all relevant hw indices at once, in a separate
|
||||
@@ -6780,29 +6890,27 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* To find SFE core idx for CSID wrapper config */
|
||||
static int cam_ife_mgr_find_sfe_core_idx(
|
||||
static int cam_ife_mgr_find_core_idx(
|
||||
int split_id,
|
||||
struct cam_ife_hw_mgr_ctx *ctx,
|
||||
enum cam_isp_hw_type hw_type,
|
||||
uint32_t *core_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ctx->num_base; i++) {
|
||||
if (ctx->base[i].hw_type != CAM_ISP_HW_TYPE_SFE)
|
||||
if (ctx->base[i].hw_type != hw_type)
|
||||
continue;
|
||||
|
||||
if (ctx->base[i].split_id == split_id) {
|
||||
CAM_DBG(CAM_ISP, "Found SFE core: %u for split_id: %d",
|
||||
ctx->base[i].idx, split_id);
|
||||
CAM_DBG(CAM_ISP, "Found core: %u for split_id: %d hw_type: %d",
|
||||
ctx->base[i].idx, split_id, hw_type);
|
||||
*core_idx = ctx->base[i].idx;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
CAM_ERR(CAM_ISP,
|
||||
"Failed to find SFE core idx for split_id %d",
|
||||
split_id);
|
||||
CAM_ERR(CAM_ISP, "Failed to find core idx for hw_type: %d split_id %d", hw_type, split_id);
|
||||
return -EINVAL;
|
||||
|
||||
end:
|
||||
@@ -6962,8 +7070,8 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
|
||||
if (ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
|
||||
csid_top_args.input_core_type =
|
||||
CAM_IFE_CSID_INPUT_CORE_SFE_IFE;
|
||||
rc = cam_ife_mgr_find_sfe_core_idx(
|
||||
i, ctx, &csid_top_args.core_idx);
|
||||
rc = cam_ife_mgr_find_core_idx(i, ctx, CAM_ISP_HW_TYPE_SFE,
|
||||
&csid_top_args.core_idx);
|
||||
if (rc)
|
||||
goto tasklet_stop;
|
||||
} else {
|
||||
@@ -7035,6 +7143,12 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
|
||||
goto safe_disable;
|
||||
}
|
||||
|
||||
rc = cam_cpas_query_drv_enable(&g_ife_hw_mgr.cam_ddr_drv_support);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_ISP, "Failed to query DRV enable rc: %d", rc);
|
||||
goto cdm_streamoff;
|
||||
}
|
||||
|
||||
start_only:
|
||||
|
||||
atomic_set(&ctx->overflow_pending, 0);
|
||||
@@ -7270,6 +7384,12 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
|
||||
/* we should called the stop hw before this already */
|
||||
cam_ife_hw_mgr_release_hw_for_ctx(ctx);
|
||||
|
||||
if (ctx->ctx_type == CAM_IFE_CTX_TYPE_SFE) {
|
||||
rc = cam_ife_mgr_update_core_info_to_cpas(ctx, false);
|
||||
if (rc)
|
||||
CAM_ERR(CAM_ISP, "Failed to update core info to cpas rc:%d", rc);
|
||||
}
|
||||
|
||||
/* reset base info */
|
||||
ctx->num_base = 0;
|
||||
memset(ctx->base, 0, sizeof(ctx->base));
|
||||
@@ -10209,6 +10329,28 @@ static int cam_isp_packet_generic_blob_handler(void *user_data,
|
||||
|
||||
}
|
||||
break;
|
||||
case CAM_ISP_GENERIC_BLOB_TYPE_DRV_CONFIG: {
|
||||
struct cam_isp_drv_config *drv_config;
|
||||
struct cam_isp_prepare_hw_update_data *prepare_hw_data;
|
||||
|
||||
if (blob_size < sizeof(struct cam_isp_drv_config)) {
|
||||
CAM_ERR(CAM_ISP, "Invalid DRV blob size %u expected %u",
|
||||
blob_size, sizeof(struct cam_isp_drv_config));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
prepare_hw_data = (struct cam_isp_prepare_hw_update_data *)
|
||||
prepare->priv;
|
||||
drv_config = (struct cam_isp_drv_config *)blob_data;
|
||||
memcpy(&prepare_hw_data->isp_drv_config, drv_config,
|
||||
sizeof(prepare_hw_data->isp_drv_config));
|
||||
|
||||
CAM_DBG(CAM_ISP, "DRV config blob en:%d timeout_val:%u path_idle_en: 0x%x",
|
||||
drv_config->drv_en, drv_config->timeout_val, drv_config->path_idle_en);
|
||||
prepare_hw_data->drv_config_valid = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type);
|
||||
break;
|
||||
@@ -14188,6 +14330,8 @@ static int cam_ife_hw_mgr_debug_register(void)
|
||||
g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_hw_mgr_perfcnter_debug);
|
||||
debugfs_create_file("ife_csid_testbus", 0644,
|
||||
g_ife_hw_mgr.debug_cfg.dentry, NULL, &cam_ife_csid_testbus_debug);
|
||||
debugfs_create_bool("disable_isp_drv", 0644, g_ife_hw_mgr.debug_cfg.dentry,
|
||||
&g_ife_hw_mgr.debug_cfg.disable_isp_drv);
|
||||
end:
|
||||
g_ife_hw_mgr.debug_cfg.enable_csid_recovery = 1;
|
||||
return rc;
|
||||
|
@@ -58,6 +58,7 @@ enum cam_ife_ctx_master_type {
|
||||
* @disable_ubwc_comp: Disable UBWC compression
|
||||
* @disable_ife_mmu_prefetch: Disable MMU prefetch for IFE bus WR
|
||||
* @rx_capture_debug_set: If rx capture debug is set by user
|
||||
* @disable_isp_drv: Disable ISP DRV config
|
||||
*
|
||||
*/
|
||||
struct cam_ife_hw_mgr_debug {
|
||||
@@ -78,6 +79,7 @@ struct cam_ife_hw_mgr_debug {
|
||||
bool disable_ubwc_comp;
|
||||
bool disable_ife_mmu_prefetch;
|
||||
bool rx_capture_debug_set;
|
||||
bool disable_isp_drv;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -420,6 +422,7 @@ struct cam_isp_sfe_cache_info {
|
||||
* @csid_rup_en Reg update at CSID side
|
||||
* @csid_global_reset_en CSID global reset enable
|
||||
* @csid_camif_irq_support CSID camif IRQ support
|
||||
* @cam_ddr_drv_support DDR DRV support
|
||||
* @isp_caps Capability of underlying SFE/IFE HW
|
||||
* @path_port_map Mapping of outport to IFE mux
|
||||
* @num_caches_found Number of caches supported
|
||||
@@ -449,6 +452,7 @@ struct cam_ife_hw_mgr {
|
||||
bool csid_rup_en;
|
||||
bool csid_global_reset_en;
|
||||
bool csid_camif_irq_support;
|
||||
bool cam_ddr_drv_support;
|
||||
struct cam_isp_ife_sfe_hw_caps isp_caps;
|
||||
struct cam_isp_hw_path_port_map path_port_map;
|
||||
|
||||
|
@@ -240,6 +240,8 @@ struct cam_isp_bw_clk_config_info {
|
||||
* @frame_header_iova: Frame header iova
|
||||
* @frame_header_res_id: Out port res_id corresponding to frame header
|
||||
* @bw_clk_config: BW and clock config info
|
||||
* @isp_drv_config: DRV config info
|
||||
* @bw_config_valid: Flag indicating if DRV config is valid for current request
|
||||
* @reg_dump_buf_desc: cmd buffer descriptors for reg dump
|
||||
* @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc
|
||||
* @packet: CSL packet from user mode driver
|
||||
@@ -255,6 +257,8 @@ struct cam_isp_prepare_hw_update_data {
|
||||
uint64_t frame_header_iova;
|
||||
uint32_t frame_header_res_id;
|
||||
struct cam_isp_bw_clk_config_info bw_clk_config;
|
||||
struct cam_isp_drv_config isp_drv_config;
|
||||
bool drv_config_valid;
|
||||
struct cam_cmd_buf_desc reg_dump_buf_desc[
|
||||
CAM_REG_DUMP_MAX_BUF_ENTRIES];
|
||||
uint32_t num_reg_dump_buf;
|
||||
|
@@ -1241,6 +1241,9 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.buf_done_irq_set_addr = 0x98,
|
||||
.test_bus_ctrl = 0x1E8,
|
||||
.test_bus_debug = 0x1EC,
|
||||
.drv_cfg0_addr = 0x13c,
|
||||
.drv_cfg1_addr = 0x140,
|
||||
.drv_cfg2_addr = 0x144,
|
||||
|
||||
/*configurations */
|
||||
.major_version = 6,
|
||||
@@ -1273,6 +1276,8 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.shdr_slave_rdi1_shift = 21,
|
||||
.shdr_master_rdi0_shift = 5,
|
||||
.shdr_master_slave_en_shift = 0,
|
||||
.drv_en_shift = 0,
|
||||
.drv_rup_en_shift = 0,
|
||||
.early_eof_supported = 1,
|
||||
.vfr_supported = 1,
|
||||
.multi_vcdt_supported = 1,
|
||||
@@ -1312,6 +1317,28 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.timestamp_enabled_in_cfg0 = true,
|
||||
.camif_irq_support = true,
|
||||
.sfe_ipp_input_rdi_res = BIT(CAM_IFE_PIX_PATH_RES_RDI_0),
|
||||
.drv_rup_en_val_map = {
|
||||
2, //RDI0
|
||||
3, //RDI1
|
||||
4, //RDI2
|
||||
5, //RDI3
|
||||
6, //RDI4
|
||||
0, //IPP
|
||||
1, //PPP
|
||||
0, //UDI0
|
||||
0, //UDI1
|
||||
0, //UDI2
|
||||
},
|
||||
.drv_path_idle_en_val_map = {
|
||||
BIT(4), //CAM_ISP_PXL_PATH
|
||||
BIT(5), //CAM_ISP_PPP_PATH
|
||||
0, // LCR not applicable
|
||||
BIT(6), //CAM_ISP_RDI0_PATH
|
||||
BIT(7), //CAM_ISP_RDI1_PATH
|
||||
BIT(8), //CAM_ISP_RDI2_PATH
|
||||
BIT(9), //CAM_ISP_RDI3_PATH
|
||||
BIT(10), //CAM_ISP_RDI4_PATH
|
||||
},
|
||||
};
|
||||
|
||||
static struct cam_ife_csid_ver2_top_reg_info
|
||||
|
@@ -1280,6 +1280,9 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.test_bus_debug = 0x11EC,
|
||||
.path_domain_id_cfg0 = 0x0,
|
||||
.path_domain_id_cfg1 = 0x4,
|
||||
.drv_cfg0_addr = 0x13c,
|
||||
.drv_cfg1_addr = 0x140,
|
||||
.drv_cfg2_addr = 0x144,
|
||||
|
||||
/*configurations */
|
||||
.major_version = 6,
|
||||
@@ -1312,6 +1315,8 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.shdr_slave_rdi1_shift = 21,
|
||||
.shdr_master_rdi0_shift = 5,
|
||||
.shdr_master_slave_en_shift = 0,
|
||||
.drv_en_shift = 0,
|
||||
.drv_rup_en_shift = 0,
|
||||
.early_eof_supported = 1,
|
||||
.vfr_supported = 1,
|
||||
.multi_vcdt_supported = 1,
|
||||
@@ -1351,6 +1356,28 @@ static struct cam_ife_csid_ver2_common_reg_info
|
||||
.timestamp_enabled_in_cfg0 = true,
|
||||
.sfe_ipp_input_rdi_res = BIT(CAM_IFE_PIX_PATH_RES_RDI_0),
|
||||
.camif_irq_support = true,
|
||||
.drv_rup_en_val_map = {
|
||||
2, //RDI0
|
||||
3, //RDI1
|
||||
4, //RDI2
|
||||
5, //RDI3
|
||||
6, //RDI4
|
||||
0, //IPP
|
||||
1, //PPP
|
||||
0, //UDI0
|
||||
0, //UDI1
|
||||
0, //UDI2
|
||||
},
|
||||
.drv_path_idle_en_val_map = {
|
||||
BIT(4), //CAM_ISP_PXL_PATH
|
||||
BIT(5), //CAM_ISP_PPP_PATH
|
||||
0, // LCR not applicable
|
||||
BIT(6), //CAM_ISP_RDI0_PATH
|
||||
BIT(7), //CAM_ISP_RDI1_PATH
|
||||
BIT(8), //CAM_ISP_RDI2_PATH
|
||||
BIT(9), //CAM_ISP_RDI3_PATH
|
||||
BIT(10), //CAM_ISP_RDI4_PATH
|
||||
},
|
||||
};
|
||||
|
||||
static struct cam_ife_csid_ver2_top_reg_info
|
||||
|
@@ -3756,6 +3756,10 @@ static int cam_ife_csid_ver1_process_cmd(void *hw_priv,
|
||||
/* Not supported for V1 */
|
||||
rc = 0;
|
||||
break;
|
||||
case CAM_ISP_HW_CMD_DRV_CONFIG:
|
||||
/* Not supported for V1 */
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
|
||||
csid_hw->hw_intf->hw_idx, cmd_type);
|
||||
|
@@ -4415,6 +4415,15 @@ int cam_ife_csid_ver2_start(void *hw_priv, void *args,
|
||||
csid_hw->flags.sof_irq_triggered = false;
|
||||
csid_hw->counters.irq_debug_cnt = 0;
|
||||
|
||||
if (start_args->is_internal_start) {
|
||||
rc = cam_cpas_csid_process_resume(csid_hw->hw_intf->hw_idx);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_ISP, "CSID:%u Failed to process resume rc: %d",
|
||||
csid_hw->hw_intf->hw_idx, rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
rc = cam_ife_csid_ver2_enable_hw(csid_hw);
|
||||
|
||||
for (i = 0; i < start_args->num_res; i++) {
|
||||
@@ -4690,7 +4699,6 @@ static int cam_ife_csid_ver2_top_cfg(
|
||||
hw_idx, top_args->input_core_type, top_args->core_idx);
|
||||
|
||||
/*config dual sync params */
|
||||
|
||||
if (csid_hw->sync_mode == CAM_ISP_HW_SYNC_NONE)
|
||||
return rc;
|
||||
else if (csid_hw->sync_mode == CAM_ISP_HW_SYNC_MASTER)
|
||||
@@ -5378,6 +5386,71 @@ static int cam_ife_csid_init_config_update(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_ife_csid_ver2_drv_config(
|
||||
struct cam_ife_csid_ver2_hw *csid_hw, void *cmd_args)
|
||||
{
|
||||
struct cam_hw_soc_info *soc_info;
|
||||
struct cam_ife_csid_ver2_reg_info *csid_reg;
|
||||
struct cam_ife_csid_drv_config_args *drv_config;
|
||||
uint32_t cfg0_val = 0, cfg1_val = 0;
|
||||
void __iomem *mem_base;
|
||||
int i;
|
||||
|
||||
if (!csid_hw || !cmd_args) {
|
||||
CAM_ERR(CAM_ISP, "Invalid params");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drv_config = (struct cam_ife_csid_drv_config_args *) cmd_args;
|
||||
soc_info = &csid_hw->hw_info->soc_info;
|
||||
csid_reg = (struct cam_ife_csid_ver2_reg_info *) csid_hw->core_info->csid_reg;
|
||||
mem_base = soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base;
|
||||
|
||||
cfg0_val = drv_config->drv_en << csid_reg->cmn_reg->drv_en_shift;
|
||||
|
||||
/* Configure DRV RUP EN for init request, one time */
|
||||
if (drv_config->is_init_config) {
|
||||
if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_IPP].res_state >=
|
||||
CAM_ISP_RESOURCE_STATE_RESERVED) {
|
||||
cfg1_val = csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_IPP];
|
||||
} else if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_RDI_0].res_state >=
|
||||
CAM_ISP_RESOURCE_STATE_RESERVED) {
|
||||
cfg1_val =
|
||||
csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_RDI_0];
|
||||
} else if (csid_hw->path_res[CAM_IFE_PIX_PATH_RES_PPP].res_state >=
|
||||
CAM_ISP_RESOURCE_STATE_RESERVED) {
|
||||
cfg1_val = csid_reg->cmn_reg->drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_PPP];
|
||||
} else {
|
||||
CAM_ERR(CAM_ISP, "Failed to configure rup_en for drv");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cam_io_w_mb(cfg1_val, mem_base + csid_reg->cmn_reg->drv_cfg1_addr);
|
||||
csid_hw->drv_init_done = true;
|
||||
}
|
||||
|
||||
if (!csid_hw->drv_init_done) {
|
||||
CAM_ERR(CAM_ISP, "Failed to update drv config, init config not done");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < CAM_ISP_MAX_PATHS; i++)
|
||||
cfg0_val |= ((drv_config->path_idle_en & BIT(i)) ?
|
||||
csid_reg->cmn_reg->drv_path_idle_en_val_map[i] : 0);
|
||||
|
||||
cam_io_w_mb(cfg0_val, mem_base + csid_reg->cmn_reg->drv_cfg0_addr);
|
||||
|
||||
cam_io_w_mb(drv_config->timeout_val, mem_base + csid_reg->cmn_reg->drv_cfg2_addr);
|
||||
|
||||
CAM_DBG(CAM_ISP,
|
||||
"CSID[%u] sfe_en:%s DRV config init_req:%s cfg0_val:0x%x cfg1_val:0x%x cfg2_val:0x%x",
|
||||
csid_hw->hw_intf->hw_idx, CAM_BOOL_TO_YESNO(csid_hw->flags.sfe_en),
|
||||
CAM_BOOL_TO_YESNO(drv_config->is_init_config), cfg0_val, cfg1_val,
|
||||
drv_config->timeout_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
|
||||
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
|
||||
{
|
||||
@@ -5468,6 +5541,9 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
|
||||
case CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE:
|
||||
rc = cam_ife_csid_init_config_update(cmd_args, arg_size);
|
||||
break;
|
||||
case CAM_ISP_HW_CMD_DRV_CONFIG:
|
||||
rc = cam_ife_csid_ver2_drv_config(csid_hw, cmd_args);
|
||||
break;
|
||||
default:
|
||||
CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
|
||||
csid_hw->hw_intf->hw_idx, cmd_type);
|
||||
|
@@ -379,6 +379,9 @@ struct cam_ife_csid_ver2_common_reg_info {
|
||||
uint32_t test_bus_debug;
|
||||
uint32_t path_domain_id_cfg0;
|
||||
uint32_t path_domain_id_cfg1;
|
||||
uint32_t drv_cfg0_addr;
|
||||
uint32_t drv_cfg1_addr;
|
||||
uint32_t drv_cfg2_addr;
|
||||
|
||||
/*Shift Bit Configurations*/
|
||||
uint32_t rst_done_shift_val;
|
||||
@@ -437,6 +440,8 @@ struct cam_ife_csid_ver2_common_reg_info {
|
||||
uint32_t shdr_slave_rdi1_shift;
|
||||
uint32_t shdr_master_rdi0_shift;
|
||||
uint32_t shdr_master_slave_en_shift;
|
||||
uint32_t drv_en_shift;
|
||||
uint32_t drv_rup_en_shift;
|
||||
/* config Values */
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
@@ -466,6 +471,8 @@ struct cam_ife_csid_ver2_common_reg_info {
|
||||
uint32_t sfe_ipp_input_rdi_res;
|
||||
bool timestamp_enabled_in_cfg0;
|
||||
bool camif_irq_support;
|
||||
uint32_t drv_rup_en_val_map[CAM_IFE_PIX_PATH_RES_MAX];
|
||||
uint32_t drv_path_idle_en_val_map[CAM_ISP_MAX_PATHS];
|
||||
|
||||
/* Masks */
|
||||
uint32_t pxl_cnt_mask;
|
||||
@@ -554,6 +561,7 @@ struct cam_ife_csid_ver2_reg_info {
|
||||
* @sync_mode: Master/Slave modes
|
||||
* @mup: MUP for incoming VC of next frame
|
||||
* @discard_frame_per_path: Count of paths dropping initial frames
|
||||
* @drv_init_done: Indicates if drv init config is done
|
||||
*
|
||||
*/
|
||||
struct cam_ife_csid_ver2_hw {
|
||||
@@ -596,6 +604,7 @@ struct cam_ife_csid_ver2_hw {
|
||||
enum cam_isp_hw_sync_mode sync_mode;
|
||||
uint32_t mup;
|
||||
atomic_t discard_frame_per_path;
|
||||
bool drv_init_done;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#define CAM_IFE_CSID_HW_NUM_MAX 8
|
||||
#define CAM_IFE_CSID_UDI_MAX 3
|
||||
#define RT_BASE_IDX 2
|
||||
#define CAM_ISP_MAX_PATHS 8
|
||||
|
||||
/**
|
||||
* enum cam_ife_csid_input_core_type - Specify the csid input core
|
||||
@@ -480,4 +481,19 @@ struct cam_ife_csid_debug_cfg_args {
|
||||
bool rx_capture_debug_set;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct cam_ife_csid_drv_config_args:
|
||||
*
|
||||
* @is_init_config: Indicator for init config
|
||||
* @drv_en: Indicator for camera DRV enable
|
||||
* @timeout_val: Timeout value from SOF to trigger up vote, given in number of GC cycles
|
||||
* @path_idle_en: Mask for paths to be considered for consolidated IDLE
|
||||
*/
|
||||
struct cam_ife_csid_drv_config_args {
|
||||
bool is_init_config;
|
||||
bool drv_en;
|
||||
uint32_t timeout_val;
|
||||
uint32_t path_idle_en;
|
||||
};
|
||||
|
||||
#endif /* _CAM_CSID_HW_INTF_H_ */
|
||||
|
@@ -216,6 +216,7 @@ enum cam_isp_hw_cmd_type {
|
||||
CAM_ISP_HW_BUS_MINI_DUMP,
|
||||
CAM_ISP_HW_USER_DUMP,
|
||||
CAM_ISP_HW_CMD_RDI_LCR_CFG,
|
||||
CAM_ISP_HW_CMD_DRV_CONFIG,
|
||||
CAM_ISP_HW_CMD_MAX,
|
||||
};
|
||||
|
||||
|
@@ -114,6 +114,7 @@ static int cam_sfe_top_set_axi_bw_vote(
|
||||
int rc = 0;
|
||||
struct cam_hw_soc_info *soc_info = NULL;
|
||||
struct cam_sfe_soc_private *soc_private = NULL;
|
||||
int i, j;
|
||||
|
||||
soc_info = top_priv->common_data.soc_info;
|
||||
soc_private = (struct cam_sfe_soc_private *)soc_info->soc_private;
|
||||
@@ -131,6 +132,38 @@ static int cam_sfe_top_set_axi_bw_vote(
|
||||
top_priv->total_bw_applied = total_bw_new_vote;
|
||||
} else {
|
||||
CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc);
|
||||
for (i = 0; i < final_bw_vote->num_paths; i++) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"sfe[%d] : Applied BW Vote : [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_priv->common_data.hw_intf->hw_idx,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
final_bw_vote->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
final_bw_vote->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
final_bw_vote->axi_path[i].vote_level),
|
||||
final_bw_vote->axi_path[i].camnoc_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ab_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ib_bw);
|
||||
}
|
||||
|
||||
for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
|
||||
for (j = 0; j < top_priv->last_bw_vote[i].num_paths; j++) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"sfe[%d] : History[%d] BW Vote : [%s][%s] [%s] [%llu %llu %llu]",
|
||||
top_priv->common_data.hw_intf->hw_idx, i,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
top_priv->last_bw_vote[i].axi_path[j].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
top_priv->last_bw_vote[i].axi_path[j].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
top_priv->last_bw_vote[i].axi_path[j].vote_level),
|
||||
top_priv->last_bw_vote[i].axi_path[j].camnoc_bw,
|
||||
top_priv->last_bw_vote[i].axi_path[j].mnoc_ab_bw,
|
||||
top_priv->last_bw_vote[i].axi_path[j].mnoc_ib_bw);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -399,13 +432,15 @@ int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv,
|
||||
|
||||
for (i = 0; i < top_priv->agg_incoming_vote.num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"sfe[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
|
||||
"sfe[%d] : New BW Vote : counter[%d] [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_priv->common_data.hw_intf->hw_idx,
|
||||
top_priv->last_bw_counter,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
top_priv->agg_incoming_vote.axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
top_priv->agg_incoming_vote.axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
top_priv->agg_incoming_vote.axi_path[i].vote_level),
|
||||
top_priv->agg_incoming_vote.axi_path[i].camnoc_bw,
|
||||
top_priv->agg_incoming_vote.axi_path[i].mnoc_ab_bw,
|
||||
top_priv->agg_incoming_vote.axi_path[i].mnoc_ib_bw);
|
||||
@@ -463,12 +498,14 @@ int cam_sfe_top_calc_axi_bw_vote(struct cam_sfe_top_priv *top_priv,
|
||||
|
||||
for (i = 0; i < final_bw_vote->num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"sfe[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
|
||||
"sfe[%d] : Apply BW Vote : [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_priv->common_data.hw_intf->hw_idx,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
final_bw_vote->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
final_bw_vote->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
final_bw_vote->axi_path[i].vote_level),
|
||||
final_bw_vote->axi_path[i].camnoc_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ab_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ib_bw);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
@@ -186,6 +187,7 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info,
|
||||
cpas_register_param.dev = soc_info->dev;
|
||||
cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb;
|
||||
cpas_register_param.userdata = soc_info;
|
||||
|
||||
rc = cam_cpas_register_client(&cpas_register_param);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc);
|
||||
@@ -252,18 +254,16 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info)
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
soc_private = soc_info->soc_private;
|
||||
|
||||
soc_private = soc_info->soc_private;
|
||||
ahb_vote.type = CAM_VOTE_ABSOLUTE;
|
||||
ahb_vote.vote.level = CAM_LOWSVS_VOTE;
|
||||
axi_vote.num_paths = 1;
|
||||
if (strnstr(soc_info->compatible, "lite",
|
||||
strlen(soc_info->compatible))) {
|
||||
axi_vote.axi_path[0].path_data_type =
|
||||
CAM_AXI_PATH_DATA_IFE_RDI1;
|
||||
if (soc_private->is_ife_lite) {
|
||||
axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_RDI1;
|
||||
} else {
|
||||
axi_vote.axi_path[0].path_data_type =
|
||||
CAM_AXI_PATH_DATA_IFE_VID;
|
||||
axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_IFE_VID;
|
||||
axi_vote.axi_path[0].vote_level = CAM_CPAS_VOTE_LEVEL_LOW;
|
||||
}
|
||||
|
||||
axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE;
|
||||
|
@@ -49,12 +49,14 @@ static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_commo
|
||||
final_bw_vote->num_paths, rc);
|
||||
for (i = 0; i < final_bw_vote->num_paths; i++) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"ife[%d] : Applied BW Vote : [%s][%s] [%llu %llu %llu]",
|
||||
"ife[%d] : Applied BW Vote : [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_common->hw_idx,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
final_bw_vote->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
final_bw_vote->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
final_bw_vote->axi_path[i].vote_level),
|
||||
final_bw_vote->axi_path[i].camnoc_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ab_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ib_bw);
|
||||
@@ -63,12 +65,14 @@ static int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_top_priv_common *top_commo
|
||||
for (i = 0; i < CAM_DELAY_CLK_BW_REDUCTION_NUM_REQ; i++) {
|
||||
for (j = 0; j < top_common->last_bw_vote[i].num_paths; j++) {
|
||||
CAM_INFO(CAM_PERF,
|
||||
"ife[%d] : History[%d] BW Vote : [%s][%s] [%llu %llu %llu]",
|
||||
"ife[%d] : History[%d] BW Vote : [%s][%s] [%s] [%llu %llu %llu]",
|
||||
top_common->hw_idx, i,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
top_common->last_bw_vote[i].axi_path[j].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
top_common->last_bw_vote[i].axi_path[j].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
top_common->last_bw_vote[i].axi_path[j].vote_level),
|
||||
top_common->last_bw_vote[i].axi_path[j].camnoc_bw,
|
||||
top_common->last_bw_vote[i].axi_path[j].mnoc_ab_bw,
|
||||
top_common->last_bw_vote[i].axi_path[j].mnoc_ib_bw);
|
||||
@@ -294,13 +298,15 @@ static int cam_vfe_top_calc_axi_bw_vote(
|
||||
|
||||
for (i = 0; i < top_common->agg_incoming_vote.num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]",
|
||||
"ife[%d] : New BW Vote : counter[%d] [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_common->hw_idx,
|
||||
top_common->last_bw_counter,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
top_common->agg_incoming_vote.axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
top_common->agg_incoming_vote.axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
top_common->agg_incoming_vote.axi_path[i].vote_level),
|
||||
top_common->agg_incoming_vote.axi_path[i].camnoc_bw,
|
||||
top_common->agg_incoming_vote.axi_path[i].mnoc_ab_bw,
|
||||
top_common->agg_incoming_vote.axi_path[i].mnoc_ib_bw);
|
||||
@@ -360,12 +366,14 @@ static int cam_vfe_top_calc_axi_bw_vote(
|
||||
|
||||
for (i = 0; i < final_bw_vote->num_paths; i++) {
|
||||
CAM_DBG(CAM_PERF,
|
||||
"ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]",
|
||||
"ife[%d] : Apply BW Vote : [%s][%s][%s] [%llu %llu %llu]",
|
||||
top_common->hw_idx,
|
||||
cam_cpas_axi_util_path_type_to_string(
|
||||
final_bw_vote->axi_path[i].path_data_type),
|
||||
cam_cpas_axi_util_trans_type_to_string(
|
||||
final_bw_vote->axi_path[i].transac_type),
|
||||
cam_cpas_axi_util_drv_vote_lvl_to_string(
|
||||
final_bw_vote->axi_path[i].vote_level),
|
||||
final_bw_vote->axi_path[i].camnoc_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ab_bw,
|
||||
final_bw_vote->axi_path[i].mnoc_ib_bw);
|
||||
|
@@ -9,11 +9,107 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <soc/qcom/rpmh.h>
|
||||
|
||||
#include "cam_compat.h"
|
||||
#include "cam_debug_util.h"
|
||||
#include "cam_cpas_api.h"
|
||||
#include "camera_main.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_USE_RPMH_DRV_API)
|
||||
#define CAM_RSC_DRV_IDENTIFIER "cam_rsc"
|
||||
|
||||
const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index)
|
||||
{
|
||||
const struct device *rsc_dev;
|
||||
|
||||
rsc_dev = rpmh_get_device(CAM_RSC_DRV_IDENTIFIER, index);
|
||||
if (!rsc_dev) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid dev for index: %u", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsc_dev;
|
||||
}
|
||||
|
||||
int cam_cpas_start_drv_for_dev(const struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!dev) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid dev for DRV enable");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = rpmh_drv_start(dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "[%s] Failed in DRV start", dev_name(dev));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cam_cpas_stop_drv_for_dev(const struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!dev) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid dev for DRV disable");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = rpmh_drv_stop(dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "[%s] Failed in DRV stop", dev_name(dev));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cam_cpas_drv_channel_switch_for_dev(const struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!dev) {
|
||||
CAM_ERR(CAM_CPAS, "Invalid dev for DRV channel switch");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = rpmh_write_sleep_and_wake_no_child(dev);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_CPAS, "[%s] Failed in DRV channel switch", dev_name(dev));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int cam_cpas_start_drv_for_dev(const struct device *dev)
|
||||
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cam_cpas_stop_drv_for_dev(const struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cam_cpas_drv_channel_switch_for_dev(const struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
|
||||
int cam_reserve_icp_fw(struct cam_fw_alloc_info *icp_fw, size_t fw_length)
|
||||
{
|
||||
|
@@ -55,6 +55,14 @@ void cam_compat_util_put_dmabuf_va(struct dma_buf *dmabuf, void *vaddr);
|
||||
void cam_smmu_util_iommu_custom(struct device *dev,
|
||||
dma_addr_t discard_start, size_t discard_length);
|
||||
|
||||
const struct device *cam_cpas_get_rsc_dev_for_drv(uint32_t index);
|
||||
|
||||
int cam_cpas_start_drv_for_dev(const struct device *dev);
|
||||
|
||||
int cam_cpas_stop_drv_for_dev(const struct device *dev);
|
||||
|
||||
int cam_cpas_drv_channel_switch_for_dev(const struct device *dev);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
|
||||
int cam_req_mgr_ordered_list_cmp(void *priv,
|
||||
const struct list_head *head_1, const struct list_head *head_2);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/msm-bus.h>
|
||||
@@ -65,7 +66,8 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
|
||||
int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
|
||||
enum cam_soc_bus_path_data bus_path_data)
|
||||
{
|
||||
int idx = 0;
|
||||
struct msm_bus_paths *path;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CAM_SOC_BUS_H_
|
||||
@@ -10,9 +11,17 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "cam_debug_util.h"
|
||||
#include "cam_cpas.h"
|
||||
|
||||
#define CAM_SOC_BUS_MAX_NUM_USECASES 8
|
||||
|
||||
enum cam_soc_bus_path_data {
|
||||
CAM_SOC_BUS_PATH_DATA_HLOS,
|
||||
CAM_SOC_BUS_PATH_DATA_DRV_HIGH,
|
||||
CAM_SOC_BUS_PATH_DATA_DRV_LOW,
|
||||
CAM_SOC_BUS_PATH_DATA_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cam_soc_bus_client_ab_ib : Bandwidth values for selected usecase
|
||||
*
|
||||
@@ -30,6 +39,7 @@ struct cam_soc_bus_client_ab_ib {
|
||||
* @name: Name of bus client
|
||||
* @src_id: Bus master/src id
|
||||
* @dst_id: Bus slave/dst id
|
||||
* @is_drv_port: If DRV bus client
|
||||
* @num_usecases: Number of use cases for this client
|
||||
* @bw_pair: Bandwidth values for applicable usecases
|
||||
*/
|
||||
@@ -37,6 +47,7 @@ struct cam_soc_bus_client_common_data {
|
||||
const char *name;
|
||||
uint32_t src_id;
|
||||
uint32_t dst_id;
|
||||
bool is_drv_port;
|
||||
int num_usecases;
|
||||
struct cam_soc_bus_client_ab_ib bw_pair[CAM_SOC_BUS_MAX_NUM_USECASES];
|
||||
};
|
||||
@@ -56,10 +67,12 @@ struct cam_soc_bus_client {
|
||||
#if IS_REACHABLE(CONFIG_QCOM_BUS_SCALING) || \
|
||||
IS_REACHABLE(CONFIG_INTERCONNECT_QCOM)
|
||||
|
||||
const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data);
|
||||
|
||||
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_update_bw(void *client, uint64_t ab, uint64_t ib,
|
||||
enum cam_soc_bus_path_data bus_path_data);
|
||||
|
||||
int cam_soc_bus_client_register(struct platform_device *pdev,
|
||||
struct device_node *dev_node, void **client,
|
||||
@@ -68,14 +81,20 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
|
||||
void cam_soc_bus_client_unregister(void **client);
|
||||
|
||||
#else
|
||||
|
||||
static const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
|
||||
enum cam_soc_bus_path_data bus_path_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interconnect.h>
|
||||
#include <dt-bindings/interconnect/qcom,icc.h>
|
||||
#include "cam_soc_bus.h"
|
||||
|
||||
/**
|
||||
@@ -12,9 +14,22 @@
|
||||
* @icc_data: Bus icc path information
|
||||
*/
|
||||
struct cam_soc_bus_client_data {
|
||||
struct icc_path *icc_data;
|
||||
struct icc_path *icc_data[CAM_SOC_BUS_PATH_DATA_MAX];
|
||||
};
|
||||
|
||||
const char *cam_soc_bus_path_data_to_str(enum cam_soc_bus_path_data bus_path_data)
|
||||
{
|
||||
switch (bus_path_data) {
|
||||
case CAM_SOC_BUS_PATH_DATA_HLOS:
|
||||
return "BUS_PATH_HLOS";
|
||||
case CAM_SOC_BUS_PATH_DATA_DRV_HIGH:
|
||||
return "BUS_PATH_DRV_HIGH";
|
||||
case CAM_SOC_BUS_PATH_DATA_DRV_LOW:
|
||||
return "BUS_PATH_DRV_LOW";
|
||||
default:
|
||||
return "BUS_PATH_INVALID";
|
||||
}
|
||||
}
|
||||
int cam_soc_bus_client_update_request(void *client, unsigned int idx)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -37,7 +52,7 @@ int cam_soc_bus_client_update_request(void *client, unsigned int idx)
|
||||
CAM_DBG(CAM_PERF, "Bus client=[%s] index[%d] ab[%llu] ib[%llu]",
|
||||
bus_client->common_data->name, idx, ab, ib);
|
||||
|
||||
rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab),
|
||||
rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS], Bps_to_icc(ab),
|
||||
Bps_to_icc(ib));
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_UTIL,
|
||||
@@ -50,7 +65,8 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
|
||||
int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib,
|
||||
enum cam_soc_bus_path_data bus_path_data)
|
||||
{
|
||||
struct cam_soc_bus_client *bus_client =
|
||||
(struct cam_soc_bus_client *) client;
|
||||
@@ -58,9 +74,10 @@ int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
|
||||
(struct cam_soc_bus_client_data *) bus_client->client_data;
|
||||
int rc = 0;
|
||||
|
||||
CAM_DBG(CAM_PERF, "Bus client=[%s] :ab[%llu] ib[%llu]",
|
||||
bus_client->common_data->name, ab, ib);
|
||||
rc = icc_set_bw(bus_client_data->icc_data, Bps_to_icc(ab),
|
||||
CAM_DBG(CAM_PERF, "Bus client=[%s] [%s] :ab[%llu] ib[%llu]",
|
||||
bus_client->common_data->name, cam_soc_bus_path_data_to_str(bus_path_data),
|
||||
ab, ib);
|
||||
rc = icc_set_bw(bus_client_data->icc_data[bus_path_data], Bps_to_icc(ab),
|
||||
Bps_to_icc(ib));
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_UTIL, "Update request failed, client[%s]",
|
||||
@@ -70,6 +87,7 @@ int cam_soc_bus_client_update_bw(void *client, uint64_t ab, uint64_t ib)
|
||||
|
||||
end:
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
int cam_soc_bus_client_register(struct platform_device *pdev,
|
||||
@@ -89,8 +107,7 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
|
||||
|
||||
*client = bus_client;
|
||||
|
||||
bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data),
|
||||
GFP_KERNEL);
|
||||
bus_client_data = kzalloc(sizeof(struct cam_soc_bus_client_data), GFP_KERNEL);
|
||||
if (!bus_client_data) {
|
||||
kfree(bus_client);
|
||||
*client = NULL;
|
||||
@@ -100,30 +117,80 @@ int cam_soc_bus_client_register(struct platform_device *pdev,
|
||||
|
||||
bus_client->client_data = bus_client_data;
|
||||
bus_client->common_data = common_data;
|
||||
bus_client_data->icc_data = icc_get(&pdev->dev,
|
||||
bus_client->common_data->src_id,
|
||||
bus_client->common_data->dst_id);
|
||||
if (IS_ERR_OR_NULL(bus_client_data->icc_data)) {
|
||||
CAM_ERR(CAM_UTIL, "failed in register bus client");
|
||||
if (bus_client->common_data->is_drv_port) {
|
||||
bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH] = icc_get(&pdev->dev,
|
||||
bus_client->common_data->src_id, bus_client->common_data->dst_id);
|
||||
if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH])) {
|
||||
CAM_ERR(CAM_UTIL,
|
||||
"Failed to register DRV bus client Bus Client=[%s] : src=%d, dst=%d bus_path:%d",
|
||||
bus_client->common_data->src_id, bus_client->common_data->dst_id,
|
||||
CAM_SOC_BUS_PATH_DATA_DRV_HIGH);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = icc_set_bw(bus_client_data->icc_data, 0, 0);
|
||||
bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW] = icc_get(&pdev->dev,
|
||||
bus_client->common_data->src_id, bus_client->common_data->dst_id);
|
||||
if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW])) {
|
||||
CAM_ERR(CAM_UTIL,
|
||||
"Failed to register DRV bus client Bus Client=[%s] : src=%d, dst=%d bus_path:%d",
|
||||
bus_client->common_data->src_id, bus_client->common_data->dst_id,
|
||||
CAM_SOC_BUS_PATH_DATA_DRV_LOW);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set appropriate tags for HIGH and LOW vote paths */
|
||||
icc_set_tag(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH],
|
||||
QCOM_ICC_TAG_ACTIVE_ONLY);
|
||||
icc_set_tag(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW],
|
||||
QCOM_ICC_TAG_SLEEP);
|
||||
|
||||
rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH], 0, 0);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_UTIL, "Bus client update request failed, rc = %d",
|
||||
rc);
|
||||
CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
|
||||
bus_client->common_data->name, rc);
|
||||
goto fail_unregister_client;
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_PERF, "Register Bus Client=[%s] : src=%d, dst=%d",
|
||||
rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW], 0, 0);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
|
||||
bus_client->common_data->name, rc);
|
||||
goto fail_unregister_client;
|
||||
}
|
||||
} else {
|
||||
bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS] = icc_get(&pdev->dev,
|
||||
bus_client->common_data->src_id, bus_client->common_data->dst_id);
|
||||
if (IS_ERR_OR_NULL(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS])) {
|
||||
CAM_ERR(CAM_UTIL, "failed to register HLOS bus client");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = icc_set_bw(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS], 0, 0);
|
||||
if (rc) {
|
||||
CAM_ERR(CAM_UTIL, "Bus client[%s] update request failed, rc = %d",
|
||||
bus_client->common_data->name, rc);
|
||||
goto fail_unregister_client;
|
||||
}
|
||||
}
|
||||
|
||||
CAM_DBG(CAM_PERF, "Register Bus Client=[%s] : src=%d, dst=%d is_drv_port:%s",
|
||||
bus_client->common_data->name, bus_client->common_data->src_id,
|
||||
bus_client->common_data->dst_id);
|
||||
bus_client->common_data->dst_id,
|
||||
CAM_BOOL_TO_YESNO(bus_client->common_data->is_drv_port));
|
||||
|
||||
return 0;
|
||||
|
||||
fail_unregister_client:
|
||||
icc_put(bus_client_data->icc_data);
|
||||
if (bus_client->common_data->is_drv_port) {
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH]);
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW]);
|
||||
} else {
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS]);
|
||||
}
|
||||
|
||||
error:
|
||||
kfree(bus_client_data);
|
||||
bus_client->client_data = NULL;
|
||||
@@ -141,7 +208,13 @@ void cam_soc_bus_client_unregister(void **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);
|
||||
if (bus_client->common_data->is_drv_port) {
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_HIGH]);
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_DRV_LOW]);
|
||||
} else {
|
||||
icc_put(bus_client_data->icc_data[CAM_SOC_BUS_PATH_DATA_HLOS]);
|
||||
}
|
||||
|
||||
kfree(bus_client_data);
|
||||
bus_client->client_data = NULL;
|
||||
kfree(bus_client);
|
||||
|
Reference in New Issue
Block a user