Loading drivers/net/wireless/cnss2/main.c +1 −0 Original line number Diff line number Diff line Loading @@ -1829,6 +1829,7 @@ static int cnss_probe(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, plat_priv); INIT_LIST_HEAD(&plat_priv->vreg_list); cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); ret = cnss_get_resources(plat_priv); Loading drivers/net/wireless/cnss2/main.h +12 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,15 @@ struct cnss_control_params { unsigned int bdf_type; }; 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; }; enum cnss_ce_index { CNSS_CE_00, CNSS_CE_01, Loading Loading @@ -298,6 +307,7 @@ struct cnss_plat_data { struct completion rddm_complete; struct completion recovery_complete; struct cnss_control_params ctrl_params; struct cnss_cpr_info cpr_info; u64 antenna; u64 grant; struct qmi_handle coex_qmi; Loading @@ -323,5 +333,7 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv); int cnss_register_ramdump(struct cnss_plat_data *plat_priv); void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv); void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv); int cnss_get_cpr_info(struct cnss_plat_data *plat_priv); int cnss_update_cpr_info(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */ drivers/net/wireless/cnss2/power.c +129 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/regulator/consumer.h> #include <soc/qcom/cmd-db.h> #include "main.h" #include "debug.h" Loading Loading @@ -39,6 +40,13 @@ static struct cnss_vreg_cfg cnss_vreg_list[] = { #define BOOTSTRAP_DELAY 1000 #define WLAN_ENABLE_DELAY 1000 #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 cnss_get_vreg_single(struct cnss_plat_data *plat_priv, struct cnss_vreg_info *vreg) { Loading Loading @@ -532,3 +540,124 @@ 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) { 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; u32 s2f_addr = 0, s6a_addr = 0; int ret = 0; res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, "tcs_cmd"); if (!res) { cnss_pr_dbg("TCS CMD address is not present for CPR\n"); goto out; } ret = cmd_db_ready(); if (ret) { cnss_pr_err("CommandDB is not ready\n"); goto out; } s2f_addr = cmd_db_read_addr("smpf2"); s6a_addr = cmd_db_read_addr("smpa6"); if (s2f_addr > 0) { cpr_info->cpr_pmic_addr = s2f_addr; cnss_pr_dbg("Get CPR PMIC address 0x%x from s2f\n", cpr_info->cpr_pmic_addr); } else if (s6a_addr > 0) { cpr_info->cpr_pmic_addr = s6a_addr; cnss_pr_dbg("Get CPR PMIC address 0x%x from s6a\n", cpr_info->cpr_pmic_addr); } else { cnss_pr_err("CPR PMIC addresses are not available\n"); 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; } int cnss_update_cpr_info(struct cnss_plat_data *plat_priv) { struct cnss_cpr_info *cpr_info = &plat_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) { cnss_pr_dbg("CPR is not enabled\n"); return 0; } if (cpr_info->voltage == 0 || cpr_info->cpr_pmic_addr == 0) { cnss_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); cnss_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) { cnss_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; cnss_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; } drivers/net/wireless/cnss2/qmi.c +6 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,12 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv) resp->fw_version_info.fw_build_timestamp, QMI_WLFW_MAX_TIMESTAMP_LEN + 1); } if (resp->voltage_mv_valid) { plat_priv->cpr_info.voltage = resp->voltage_mv; cnss_pr_dbg("Voltage for CPR: %dmV\n", plat_priv->cpr_info.voltage); cnss_update_cpr_info(plat_priv); } if (resp->otp_version_valid) plat_priv->otp_version = resp->otp_version; Loading Loading
drivers/net/wireless/cnss2/main.c +1 −0 Original line number Diff line number Diff line Loading @@ -1829,6 +1829,7 @@ static int cnss_probe(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, plat_priv); INIT_LIST_HEAD(&plat_priv->vreg_list); cnss_get_cpr_info(plat_priv); cnss_init_control_params(plat_priv); ret = cnss_get_resources(plat_priv); Loading
drivers/net/wireless/cnss2/main.h +12 −0 Original line number Diff line number Diff line Loading @@ -231,6 +231,15 @@ struct cnss_control_params { unsigned int bdf_type; }; 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; }; enum cnss_ce_index { CNSS_CE_00, CNSS_CE_01, Loading Loading @@ -298,6 +307,7 @@ struct cnss_plat_data { struct completion rddm_complete; struct completion recovery_complete; struct cnss_control_params ctrl_params; struct cnss_cpr_info cpr_info; u64 antenna; u64 grant; struct qmi_handle coex_qmi; Loading @@ -323,5 +333,7 @@ void cnss_unregister_subsys(struct cnss_plat_data *plat_priv); int cnss_register_ramdump(struct cnss_plat_data *plat_priv); void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv); void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv); int cnss_get_cpr_info(struct cnss_plat_data *plat_priv); int cnss_update_cpr_info(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */
drivers/net/wireless/cnss2/power.c +129 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/regulator/consumer.h> #include <soc/qcom/cmd-db.h> #include "main.h" #include "debug.h" Loading Loading @@ -39,6 +40,13 @@ static struct cnss_vreg_cfg cnss_vreg_list[] = { #define BOOTSTRAP_DELAY 1000 #define WLAN_ENABLE_DELAY 1000 #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 cnss_get_vreg_single(struct cnss_plat_data *plat_priv, struct cnss_vreg_info *vreg) { Loading Loading @@ -532,3 +540,124 @@ 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) { 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; u32 s2f_addr = 0, s6a_addr = 0; int ret = 0; res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, "tcs_cmd"); if (!res) { cnss_pr_dbg("TCS CMD address is not present for CPR\n"); goto out; } ret = cmd_db_ready(); if (ret) { cnss_pr_err("CommandDB is not ready\n"); goto out; } s2f_addr = cmd_db_read_addr("smpf2"); s6a_addr = cmd_db_read_addr("smpa6"); if (s2f_addr > 0) { cpr_info->cpr_pmic_addr = s2f_addr; cnss_pr_dbg("Get CPR PMIC address 0x%x from s2f\n", cpr_info->cpr_pmic_addr); } else if (s6a_addr > 0) { cpr_info->cpr_pmic_addr = s6a_addr; cnss_pr_dbg("Get CPR PMIC address 0x%x from s6a\n", cpr_info->cpr_pmic_addr); } else { cnss_pr_err("CPR PMIC addresses are not available\n"); 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; } int cnss_update_cpr_info(struct cnss_plat_data *plat_priv) { struct cnss_cpr_info *cpr_info = &plat_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) { cnss_pr_dbg("CPR is not enabled\n"); return 0; } if (cpr_info->voltage == 0 || cpr_info->cpr_pmic_addr == 0) { cnss_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); cnss_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) { cnss_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; cnss_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; }
drivers/net/wireless/cnss2/qmi.c +6 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,12 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv) resp->fw_version_info.fw_build_timestamp, QMI_WLFW_MAX_TIMESTAMP_LEN + 1); } if (resp->voltage_mv_valid) { plat_priv->cpr_info.voltage = resp->voltage_mv; cnss_pr_dbg("Voltage for CPR: %dmV\n", plat_priv->cpr_info.voltage); cnss_update_cpr_info(plat_priv); } if (resp->otp_version_valid) plat_priv->otp_version = resp->otp_version; Loading