From 852e8b2ffe6528408c343560470e84553c1c5fb3 Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Tue, 28 Jul 2020 09:24:02 -0700 Subject: [PATCH] cnss2: Add support of runtime Vreg enable for QCA6490 QCA6490 with internal regulator configuration needs additional voltage regulator to be enabled. Update platform driver to get the config from BDF using QMI and enable it in TCS accordingly. Change-Id: Idb93fb95d46696f943f166e31cf50dc5b3b0da97 Signed-off-by: Manikandan Mohan --- drivers/net/wireless/cnss2/main.c | 1 + drivers/net/wireless/cnss2/main.h | 10 ++- drivers/net/wireless/cnss2/power.c | 102 +++++++++++++++++++++-------- drivers/net/wireless/cnss2/qmi.c | 6 ++ 4 files changed, 89 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index f528e73b6538..b999d28b1c9e 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -2298,6 +2298,7 @@ static int cnss_probe(struct platform_device *plat_dev) INIT_LIST_HEAD(&plat_priv->clk_list); cnss_get_wlaon_pwr_ctrl_info(plat_priv); + cnss_get_tcs_info(plat_priv); cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index be90950b7cec..4f04638fd25a 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -305,10 +305,13 @@ struct cnss_control_params { unsigned int time_sync_period; }; +struct cnss_tcs_info { + resource_size_t cmd_base_addr; + void __iomem *cmd_base_addr_io; +}; + struct cnss_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; @@ -401,6 +404,7 @@ struct cnss_plat_data { bool cbc_enabled; u8 use_nv_mac; u8 set_wlaon_pwr_ctrl; + struct cnss_tcs_info tcs_info; }; #ifdef CONFIG_ARCH_QCOM @@ -458,5 +462,7 @@ int cnss_minidump_add_region(struct cnss_plat_data *plat_priv, int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv, enum cnss_fw_dump_type type, int seg_no, void *va, phys_addr_t pa, size_t size); +int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv); +int cnss_get_tcs_info(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */ diff --git a/drivers/net/wireless/cnss2/power.c b/drivers/net/wireless/cnss2/power.c index a224d075e10d..9d26835b407f 100644 --- a/drivers/net/wireless/cnss2/power.c +++ b/drivers/net/wireless/cnss2/power.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -10,6 +10,7 @@ #include "main.h" #include "debug.h" +#include "bus.h" static struct cnss_vreg_cfg cnss_vreg_list[] = { {"vdd-wlan-core", 1300000, 1300000, 0, 0, 0}, @@ -832,15 +833,12 @@ void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv) plat_priv->pin_result.host_pin_result = pin_status; } -int cnss_get_cpr_info(struct cnss_plat_data *plat_priv) +int cnss_get_tcs_info(struct cnss_plat_data *plat_priv) { struct platform_device *plat_dev = plat_priv->plat_dev; - struct cnss_cpr_info *cpr_info = &plat_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"); @@ -849,6 +847,37 @@ int cnss_get_cpr_info(struct cnss_plat_data *plat_priv) goto out; } + plat_priv->tcs_info.cmd_base_addr = res->start; + addr_len = resource_size(res); + cnss_pr_dbg("TCS CMD base address is %pa with length %pa\n", + &plat_priv->tcs_info.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); + cnss_pr_err("Failed to map TCS CMD address, err = %d\n", + ret); + goto out; + } + plat_priv->tcs_info.cmd_base_addr_io = tcs_cmd_base_addr; + return 0; +out: + return ret; +} + +int cnss_get_cpr_info(struct cnss_plat_data *plat_priv) +{ + struct platform_device *plat_dev = plat_priv->plat_dev; + struct cnss_cpr_info *cpr_info = &plat_priv->cpr_info; + const char *cmd_db_name; + u32 cpr_pmic_addr = 0; + int ret = 0; + + if (plat_priv->tcs_info.cmd_base_addr == 0) { + cnss_pr_dbg("TCS CMD not configured\n"); + return 0; + } + ret = of_property_read_string(plat_dev->dev.of_node, "qcom,cmd_db_name", &cmd_db_name); if (ret) { @@ -873,24 +902,7 @@ int cnss_get_cpr_info(struct cnss_plat_data *plat_priv) ret = -EINVAL; goto out; } - - cpr_info->tcs_cmd_base_addr = res->start; - addr_len = resource_size(res); - cnss_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); - cnss_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; } @@ -902,8 +914,8 @@ int cnss_update_cpr_info(struct cnss_plat_data *plat_priv) void __iomem *tcs_cmd_addr, *tcs_cmd_data_addr; int i, j; - if (cpr_info->tcs_cmd_base_addr == 0) { - cnss_pr_dbg("CPR is not enabled\n"); + if (plat_priv->tcs_info.cmd_base_addr == 0) { + cnss_pr_dbg("TCS CMD not configured\n"); return 0; } @@ -919,7 +931,8 @@ int cnss_update_cpr_info(struct cnss_plat_data *plat_priv) 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; + tcs_cmd_addr = plat_priv->tcs_info.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 + @@ -931,9 +944,8 @@ int cnss_update_cpr_info(struct cnss_plat_data *plat_priv) 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; + plat_priv->tcs_info.cmd_base_addr + + offset + TCS_CMD_DATA_ADDR_OFFSET; cpr_info->tcs_cmd_data_addr_io = tcs_cmd_data_addr; } @@ -955,3 +967,37 @@ update_cpr: return 0; } + +int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv) +{ + struct platform_device *plat_dev = plat_priv->plat_dev; + u32 offset, addr_val, data_val; + void __iomem *tcs_cmd; + int ret; + + if (!plat_priv->tcs_info.cmd_base_addr_io) { + cnss_pr_err("TCS CMD not configured\n"); + return -EINVAL; + } + + if (plat_priv->device_id != QCA6490_DEVICE_ID) + return -EINVAL; + + ret = of_property_read_u32(plat_dev->dev.of_node, + "qcom,tcs_offset_int_pow_amp_vreg", + &offset); + if (ret) { + cnss_pr_dbg("Internal Power Amp Vreg not configured\n"); + return -EINVAL; + } + tcs_cmd = plat_priv->tcs_info.cmd_base_addr_io + offset; + addr_val = readl_relaxed(tcs_cmd); + tcs_cmd += TCS_CMD_DATA_ADDR_OFFSET; + + /* 1 = enable Vreg */ + writel_relaxed(1, tcs_cmd); + + data_val = readl_relaxed(tcs_cmd); + cnss_pr_dbg("Setup S3E TCS Addr: %x Data: %d\n", addr_val, data_val); + return 0; +} diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index c4f3f42a38ab..30b13b1651f9 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -632,6 +632,12 @@ bypass_bdf: if (bdf_type != CNSS_BDF_DUMMY) release_firmware(fw_entry); + /* QCA6490 enable S3E regulator for IPA configuration only */ + if (resp->host_bdf_data_valid) { + if (!(resp->host_bdf_data & QMI_WLFW_HW_XPA_V01)) + cnss_enable_int_pow_amp_vreg(plat_priv); + } + kfree(req); kfree(resp); return 0;