msm: camera: cpas: Enable icp clk for qchannel handshake

For some chipsets, qchannel handshake needs icp clk to be
enabled. Add support to enable icp clk while qchannel
handshake by adding as optional clk in cpas node. Whether
to enable icp clk or not is controlled through workaround
list populated for each chipset.
Add mechanism to retry qchannel acceptance if the first
auto try has failed, by explicity writing 0x1 to qchannel
ctrl register. This will bring back qchannel to good state.

CRs-Fixed: 3131613
Change-Id: Ie39a9789b2eb1bf9c0f6adb26fe6d6e1823eff70
Signed-off-by: Pavan Kumar Chilamkurthi <quic_pchilamk@quicinc.com>
这个提交包含在:
Pavan Kumar Chilamkurthi
2022-02-15 22:56:35 -08:00
提交者 Camera Software Integration
父节点 c885a64448
当前提交 a32a315e54
修改 9 个文件,包含 152 行新增16 行删除

查看文件

@@ -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/device.h>
@@ -1633,6 +1634,7 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
int rc, i = 0;
struct cam_cpas_private_soc *soc_private = NULL;
bool invalid_start = true;
int count;
if (!hw_priv || !start_args) {
CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -1746,6 +1748,11 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
goto remove_ahb_vote;
atomic_set(&cpas_core->irq_count, 1);
count = cam_soc_util_regulators_enabled(&cpas_hw->soc_info);
if (count > 0)
CAM_DBG(CAM_CPAS, "Regulators already enabled %d", count);
rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
applied_level);
if (rc) {
@@ -1754,6 +1761,24 @@ static int cam_cpas_hw_start(void *hw_priv, void *start_args,
goto remove_axi_vote;
}
if (cpas_core->internal_ops.qchannel_handshake) {
rc = cpas_core->internal_ops.qchannel_handshake(cpas_hw, true, false);
if (rc) {
CAM_WARN(CAM_CPAS, "failed in qchannel_handshake rc=%d", rc);
/* Do not return error, passthrough */
rc = cpas_core->internal_ops.qchannel_handshake(cpas_hw,
true, true);
if (rc) {
CAM_ERR(CAM_CPAS,
"failed in qchannel_handshake, hw blocks may not work rc=%d",
rc);
/* Do not return error, passthrough */
}
rc = 0;
}
}
if (cpas_core->internal_ops.power_on) {
rc = cpas_core->internal_ops.power_on(cpas_hw);
if (rc) {
@@ -1831,7 +1856,7 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
struct cam_ahb_vote ahb_vote;
struct cam_axi_vote axi_vote = {0};
struct cam_cpas_private_soc *soc_private = NULL;
int rc = 0;
int rc = 0, count;
long result;
int retry_camnoc_idle = 0;
@@ -1888,12 +1913,9 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
}
if (cpas_core->internal_ops.qchannel_handshake) {
rc = cpas_core->internal_ops.qchannel_handshake(
cpas_hw, false);
rc = cpas_core->internal_ops.qchannel_handshake(cpas_hw, false, false);
if (rc) {
CAM_ERR(CAM_CPAS,
"failed in qchannel_handshake rc=%d",
rc);
CAM_ERR(CAM_CPAS, "failed in qchannel_handshake rc=%d", rc);
retry_camnoc_idle = 1;
/* Do not return error, passthrough */
}
@@ -1917,12 +1939,9 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
/* try again incase camnoc is still not idle */
if (cpas_core->internal_ops.qchannel_handshake &&
retry_camnoc_idle) {
rc = cpas_core->internal_ops.qchannel_handshake(
cpas_hw, false);
rc = cpas_core->internal_ops.qchannel_handshake(cpas_hw, false, false);
if (rc) {
CAM_ERR(CAM_CPAS,
"failed in qchannel_handshake rc=%d",
rc);
CAM_ERR(CAM_CPAS, "failed in qchannel_handshake rc=%d", rc);
/* Do not return error, passthrough */
}
}
@@ -1935,6 +1954,14 @@ static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
}
CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d",
atomic_read(&cpas_core->irq_count));
count = cam_soc_util_regulators_enabled(&cpas_hw->soc_info);
if (count > 0)
CAM_WARN(CAM_CPAS,
"Client=[%d][%s][%d] qchannel shut down while top gdsc is still on %d",
client_indx, cpas_client->data.identifier,
cpas_client->data.cell_index, count);
cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
}

查看文件

@@ -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_H_
@@ -92,7 +93,7 @@ struct cam_cpas_internal_ops {
int (*setup_qos_settings)(struct cam_hw_info *cpas_hw,
uint32_t selection_mask);
int (*print_poweron_settings)(struct cam_hw_info *cpas_hw);
int (*qchannel_handshake)(struct cam_hw_info *cpas_hw, bool power_on);
int (*qchannel_handshake)(struct cam_hw_info *cpas_hw, bool power_on, bool force_on);
};
/**

查看文件

@@ -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/device.h>
@@ -20,6 +21,8 @@
static uint cpas_dump;
module_param(cpas_dump, uint, 0644);
#define CAM_ICP_CLK_NAME "cam_icp_clk"
void cam_cpas_dump_axi_vote_info(
const struct cam_cpas_client *cpas_client,
const char *identifier,
@@ -1203,6 +1206,7 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
irq_handler_t irq_handler, struct cam_hw_info *cpas_hw)
{
int rc = 0;
struct cam_cpas_private_soc *soc_private;
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc) {
@@ -1237,6 +1241,18 @@ int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info,
goto free_soc_private;
}
soc_private = (struct cam_cpas_private_soc *)soc_info->soc_private;
rc = cam_soc_util_get_option_clk_by_name(soc_info, CAM_ICP_CLK_NAME,
&soc_private->icp_clk_index);
if (rc) {
CAM_DBG(CAM_CPAS, "Option clk get failed with rc %d", rc);
soc_private->icp_clk_index = -1;
rc = 0;
} else {
CAM_DBG(CAM_CPAS, "Option clk get success index %d", soc_private->icp_clk_index);
}
return rc;
free_soc_private:
@@ -1254,6 +1270,12 @@ int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info)
for (i = 0; i < soc_private->num_caches; i++)
llcc_slice_putd(soc_private->llcc_info[i].slic_desc);
if (soc_private->icp_clk_index != -1) {
rc = cam_soc_util_put_optional_clk(soc_info, soc_private->icp_clk_index);
if (rc)
CAM_ERR(CAM_CPAS, "Error Put optional clk failed rc=%d", rc);
}
rc = cam_soc_util_release_platform_resource(soc_info);
if (rc)
CAM_ERR(CAM_CPAS, "release platform failed, rc=%d", rc);

查看文件

@@ -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_SOC_H_
@@ -163,6 +164,7 @@ struct cam_cpas_smart_qos_info {
* @llcc_info: Cache info
* @enable_smart_qos: Whether to enable Smart QoS mechanism on current chipset
* @smart_qos_info: Pointer to smart qos info
* @icp_clk_index: Index of optional icp clk
*/
struct cam_cpas_private_soc {
const char *arch_compat;
@@ -187,6 +189,7 @@ struct cam_cpas_private_soc {
struct cam_sys_cache_info *llcc_info;
bool enable_smart_qos;
struct cam_cpas_smart_qos_info *smart_qos_info;
int32_t icp_clk_index;
};
void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private);

查看文件

@@ -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/delay.h>
@@ -922,14 +923,19 @@ static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
}
static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
bool power_on)
bool power_on, bool force_on)
{
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
uint32_t mask = 0;
uint32_t wait_data, qchannel_status, qdeny;
int rc = 0;
int rc = 0, ret = 0;
struct cam_cpas_private_soc *soc_private =
(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
struct cam_cpas_hw_errata_wa_list *errata_wa_list =
camnoc_info->errata_wa_list;
bool icp_clk_enabled = false;
if (reg_indx == -1)
return -EINVAL;
@@ -937,7 +943,28 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
if (!qchannel_info)
return 0;
if (errata_wa_list && errata_wa_list->enable_icp_clk_for_qchannel.enable) {
CAM_DBG(CAM_CPAS, "Enabling ICP clk for qchannel handshake");
if (soc_private->icp_clk_index == -1) {
CAM_ERR(CAM_CPAS,
"ICP clock not added as optional clk, qchannel handshake will fail");
} else {
ret = cam_soc_util_clk_enable(soc_info, true, soc_private->icp_clk_index,
-1, NULL);
if (ret)
CAM_ERR(CAM_CPAS, "Error enable icp clk failed rc=%d", ret);
else
icp_clk_enabled = true;
}
}
if (power_on) {
if (force_on) {
cam_io_w_mb(0x1,
soc_info->reg_map[reg_indx].mem_base + qchannel_info->qchannel_ctrl);
CAM_DBG(CAM_CPAS, "Force qchannel on");
}
/* wait for QACCEPTN in QCHANNEL status*/
mask = BIT(0);
wait_data = 1;
@@ -957,20 +984,30 @@ static int cam_cpastop_qchannel_handshake(struct cam_hw_info *cpas_hw,
CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
if (rc) {
CAM_ERR(CAM_CPAS,
"camnoc idle sequence failed, qstat 0x%x",
"CPAS_%s camnoc idle sequence failed, qstat 0x%x",
power_on ? "START" : "STOP",
cam_io_r(soc_info->reg_map[reg_indx].mem_base +
qchannel_info->qchannel_status));
/* Do not return error, passthrough */
rc = 0;
}
/* check if deny bit is set */
qchannel_status = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base +
qchannel_info->qchannel_status);
CAM_DBG(CAM_CPAS, "CPAS_%s : qchannel status 0x%x", power_on ? "START" : "STOP",
qchannel_status);
qdeny = (qchannel_status & BIT(1));
if (!power_on && qdeny)
rc = -EBUSY;
if (icp_clk_enabled) {
ret = cam_soc_util_clk_disable(soc_info, true, soc_private->icp_clk_index);
if (ret)
CAM_ERR(CAM_CPAS, "Error disable icp clk failed rc=%d", rc);
}
return rc;
}

查看文件

@@ -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_CPASTOP_HW_H_
@@ -298,10 +299,12 @@ struct cam_cpas_hw_errata_wa {
* camnoc slave pending transactions before turning off CPAS_TOP gdsc
* @tcsr_camera_hf_sf_ares_glitch: Errata workaround info from ignoring
* erroneous signals at camera start
* @enable_icp_clk_for_qchannel: Need to enable ICP clk while qchannel handshake
*/
struct cam_cpas_hw_errata_wa_list {
struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans;
struct cam_cpas_hw_errata_wa tcsr_camera_hf_sf_ares_glitch;
struct cam_cpas_hw_errata_wa enable_icp_clk_for_qchannel;
};
/**

查看文件

@@ -1,6 +1,7 @@
/* 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.
*/
#ifndef _CPASTOP_V780_100_H_
@@ -1191,6 +1192,9 @@ static struct cam_cpas_hw_errata_wa_list cam780_cpas100_errata_wa_list = {
.value = 0, /* expected to be 0 */
},
},
.enable_icp_clk_for_qchannel = {
.enable = true,
},
};
static struct cam_camnoc_info cam780_cpas100_camnoc_info = {

查看文件

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/of.h>
@@ -3629,3 +3630,28 @@ int cam_soc_util_print_clk_freq(struct cam_hw_soc_info *soc_info)
return 0;
}
int cam_soc_util_regulators_enabled(struct cam_hw_soc_info *soc_info)
{
int j = 0, rc = 0;
int enabled_cnt = 0;
for (j = 0; j < soc_info->num_rgltr; j++) {
if (soc_info->rgltr[j]) {
rc = regulator_is_enabled(soc_info->rgltr[j]);
if (rc < 0) {
CAM_ERR(CAM_UTIL, "%s regulator_is_enabled failed",
soc_info->rgltr_name[j]);
} else if (rc > 0) {
CAM_DBG(CAM_UTIL, "%s regulator enabled",
soc_info->rgltr_name[j]);
enabled_cnt++;
} else {
CAM_DBG(CAM_UTIL, "%s regulator is disabled",
soc_info->rgltr_name[j]);
}
}
}
return enabled_cnt;
}

查看文件

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CAM_SOC_UTIL_H_
@@ -773,4 +774,16 @@ int cam_soc_util_print_clk_freq(struct cam_hw_soc_info *soc_info);
int cam_soc_util_select_pinctrl_state(
struct cam_hw_soc_info *soc_info, int idx, bool active);
/**
* cam_soc_util_print_clk_freq()
*
* @brief: This function checks whether regulators of this device are enabled at this
* time.
*
* @soc_info: Device soc struct to be populated
*
* @return: Number of regulators enabled
*/
int cam_soc_util_regulators_enabled(struct cam_hw_soc_info *soc_info);
#endif /* _CAM_SOC_UTIL_H_ */