Merge "icnss2: Add open loop CPR support"

This commit is contained in:
qctecmdr 2020-10-13 09:54:30 -07:00 • committed by Gerrit - the friendly Code Review server
commit f9790cb371
4 changed files with 147 additions and 0 deletions

View file

@ -3267,6 +3267,7 @@ static int icnss_probe(struct platform_device *pdev)
icnss_pr_err("ICNSS genl init failed %d\n", ret);
icnss_runtime_pm_init(priv);
icnss_get_cpr_info(priv);
}
INIT_LIST_HEAD(&priv->icnss_tcdev_list);

View file

@ -133,6 +133,15 @@ struct icnss_vreg_info {
u32 enabled;
};
struct icnss_cpr_info {
resource_size_t tcs_cmd_base_addr;
resource_size_t tcs_cmd_data_addr;
void __iomem *tcs_cmd_base_addr_io;
void __iomem *tcs_cmd_data_addr_io;
u32 cpr_pmic_addr;
u32 voltage;
};
enum icnss_vreg_type {
ICNSS_VREG_PRIM,
};
@ -307,6 +316,7 @@ struct icnss_priv {
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
struct list_head vreg_list;
struct list_head clk_list;
struct icnss_cpr_info cpr_info;
unsigned long device_id;
struct icnss_msi_config *msi_config;
u32 msi_base_data;
@ -419,5 +429,7 @@ int icnss_soc_wake_event_post(struct icnss_priv *priv,
u32 flags, void *data);
int icnss_get_iova(struct icnss_priv *priv, u64 *addr, u64 *size);
int icnss_get_iova_ipa(struct icnss_priv *priv, u64 *addr, u64 *size);
int icnss_get_cpr_info(struct icnss_priv *priv);
int icnss_update_cpr_info(struct icnss_priv *priv);
#endif

View file

@ -8,6 +8,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
#include <soc/qcom/cmd-db.h>
#include <linux/io.h>
#include "main.h"
#include "qmi.h"
#include "debug.h"
@ -45,6 +46,13 @@ static struct icnss_clk_cfg icnss_adrestea_clk_list[] = {
#define ICNSS_THRESHOLD_LOW 3450000
#define ICNSS_THRESHOLD_GUARD 20000
#define TCS_CMD_DATA_ADDR_OFFSET 0x4
#define TCS_OFFSET 0xC8
#define TCS_CMD_OFFSET 0x10
#define MAX_TCS_NUM 8
#define MAX_TCS_CMD_NUM 5
#define BT_CXMX_VOLTAGE_MV 950
static int icnss_get_vreg_single(struct icnss_priv *priv,
struct icnss_vreg_info *vreg)
{
@ -801,3 +809,121 @@ int icnss_init_vph_monitor(struct icnss_priv *priv)
out:
return ret;
}
int icnss_get_cpr_info(struct icnss_priv *priv)
{
struct platform_device *plat_dev = priv->pdev;
struct icnss_cpr_info *cpr_info = &priv->cpr_info;
struct resource *res;
resource_size_t addr_len;
void __iomem *tcs_cmd_base_addr;
const char *cmd_db_name;
u32 cpr_pmic_addr = 0;
int ret = 0;
res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, "tcs_cmd");
if (!res) {
icnss_pr_dbg("TCS CMD address is not present for CPR\n");
goto out;
}
ret = of_property_read_string(plat_dev->dev.of_node,
"qcom,cmd_db_name", &cmd_db_name);
if (ret) {
icnss_pr_dbg("CommandDB name is not present for CPR\n");
goto out;
}
cpr_pmic_addr = cmd_db_read_addr(cmd_db_name);
if (cpr_pmic_addr > 0) {
cpr_info->cpr_pmic_addr = cpr_pmic_addr;
icnss_pr_dbg("Get CPR PMIC address 0x%x from %s\n",
cpr_info->cpr_pmic_addr, cmd_db_name);
} else {
icnss_pr_err("CPR PMIC address is not available for %s\n",
cmd_db_name);
ret = -EINVAL;
goto out;
}
cpr_info->tcs_cmd_base_addr = res->start;
addr_len = resource_size(res);
icnss_pr_dbg("TCS CMD base address is %pa with length %pa\n",
&cpr_info->tcs_cmd_base_addr, &addr_len);
tcs_cmd_base_addr = devm_ioremap_resource(&plat_dev->dev, res);
if (IS_ERR(tcs_cmd_base_addr)) {
ret = PTR_ERR(tcs_cmd_base_addr);
icnss_pr_err("Failed to map TCS CMD address, err = %d\n",
ret);
goto out;
}
cpr_info->tcs_cmd_base_addr_io = tcs_cmd_base_addr;
return 0;
out:
return ret;
}
int icnss_update_cpr_info(struct icnss_priv *priv)
{
struct icnss_cpr_info *cpr_info = &priv->cpr_info;
u32 pmic_addr, voltage = 0, voltage_tmp, offset;
void __iomem *tcs_cmd_addr, *tcs_cmd_data_addr;
int i, j;
if (cpr_info->tcs_cmd_base_addr == 0) {
icnss_pr_dbg("CPR is not enabled\n");
return 0;
}
if (cpr_info->voltage == 0 || cpr_info->cpr_pmic_addr == 0) {
icnss_pr_err("Voltage %dmV or PMIC address 0x%x is not valid\n",
cpr_info->voltage, cpr_info->cpr_pmic_addr);
return -EINVAL;
}
if (cpr_info->tcs_cmd_data_addr_io)
goto update_cpr;
for (i = 0; i < MAX_TCS_NUM; i++) {
for (j = 0; j < MAX_TCS_CMD_NUM; j++) {
offset = i * TCS_OFFSET + j * TCS_CMD_OFFSET;
tcs_cmd_addr = cpr_info->tcs_cmd_base_addr_io + offset;
pmic_addr = readl_relaxed(tcs_cmd_addr);
if (pmic_addr == cpr_info->cpr_pmic_addr) {
tcs_cmd_data_addr = tcs_cmd_addr +
TCS_CMD_DATA_ADDR_OFFSET;
voltage_tmp = readl_relaxed(tcs_cmd_data_addr);
icnss_pr_dbg("Got voltage %dmV from i: %d, j: %d\n",
voltage_tmp, i, j);
if (voltage_tmp > voltage) {
voltage = voltage_tmp;
cpr_info->tcs_cmd_data_addr =
cpr_info->tcs_cmd_base_addr +
offset +
TCS_CMD_DATA_ADDR_OFFSET;
cpr_info->tcs_cmd_data_addr_io =
tcs_cmd_data_addr;
}
}
}
}
if (!cpr_info->tcs_cmd_data_addr_io) {
icnss_pr_err("Failed to find proper TCS CMD data address\n");
return -EINVAL;
}
update_cpr:
cpr_info->voltage = cpr_info->voltage > BT_CXMX_VOLTAGE_MV ?
cpr_info->voltage : BT_CXMX_VOLTAGE_MV;
icnss_pr_dbg("Update TCS CMD data address %pa with voltage %dmV\n",
&cpr_info->tcs_cmd_data_addr, cpr_info->voltage);
writel_relaxed(cpr_info->voltage, cpr_info->tcs_cmd_data_addr_io);
return 0;
}

View file

@ -674,6 +674,14 @@ int wlfw_cap_send_sync_msg(struct icnss_priv *priv)
resp->fw_version_info.fw_build_timestamp,
WLFW_MAX_TIMESTAMP_LEN + 1);
}
if (resp->voltage_mv_valid) {
priv->cpr_info.voltage = resp->voltage_mv;
icnss_pr_dbg("Voltage for CPR: %dmV\n",
priv->cpr_info.voltage);
icnss_update_cpr_info(priv);
}
if (resp->fw_build_id_valid)
strlcpy(priv->fw_build_id, resp->fw_build_id,
QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1);