Merge 4f03c58310
on remote branch
Change-Id: I92a9213e9c300f9811e744169af6ad4d2d0fb1a0
Bu işleme şunda yer alıyor:
8
Kbuild
8
Kbuild
@@ -36,6 +36,14 @@ ifeq ($(CONFIG_CNSS2_CONDITIONAL_POWEROFF),y)
|
||||
KBUILD_CPPFLAGS += -DCONFIG_CNSS2_CONDITIONAL_POWEROFF
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CNSS_REQ_FW_DIRECT),y)
|
||||
KBUILD_CPPFLAGS += -DCONFIG_CNSS_REQ_FW_DIRECT
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CNSS_SUPPORT_DUAL_DEV),y)
|
||||
KBUILD_CPPFLAGS += -DCONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_AUTO_PROJECT),y)
|
||||
KBUILD_CPPFLAGS += -DCONFIG_PULLDOWN_WLANEN
|
||||
endif
|
||||
|
13
Makefile
13
Makefile
@@ -11,14 +11,11 @@ WLAN_PLATFORM_ROOT = $(shell pwd)
|
||||
KBUILD_OPTIONS := WLAN_PLATFORM_ROOT=$(WLAN_PLATFORM_ROOT)
|
||||
ifeq ($(USE_EXTERNAL_CONFIGS),)
|
||||
KBUILD_OPTIONS += CONFIG_CNSS_OUT_OF_TREE=y
|
||||
|
||||
ifneq (,$(filter $(CONFIG_PCI_MSM),y m))
|
||||
KBUILD_OPTIONS += CONFIG_CNSS2=m
|
||||
KBUILD_OPTIONS += CONFIG_CNSS2_QMI=y
|
||||
KBUILD_OPTIONS += CONFIG_CNSS2_DEBUG=y
|
||||
endif
|
||||
KBUILD_OPTIONS += CONFIG_ICNSS2=m
|
||||
KBUILD_OPTIONS += CONFIG_CNSS2_QMI=y
|
||||
KBUILD_OPTIONS += CONFIG_ICNSS2_QMI=y
|
||||
KBUILD_OPTIONS += CONFIG_CNSS2_DEBUG=y
|
||||
KBUILD_OPTIONS += CONFIG_ICNSS2_DEBUG=y
|
||||
KBUILD_OPTIONS += CONFIG_CNSS_QMI_SVC=m
|
||||
KBUILD_OPTIONS += CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
|
||||
@@ -29,8 +26,10 @@ KBUILD_OPTIONS += CONFIG_CNSS2_SSR_DRIVER_DUMP=y
|
||||
endif
|
||||
endif
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
|
||||
all: modules
|
||||
|
||||
%:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
|
||||
|
@@ -97,6 +97,14 @@ config CNSS_REQ_FW_DIRECT
|
||||
configuration file to avoid 60s timeout while search file under user
|
||||
space failure.
|
||||
|
||||
config CNSS_SUPPORT_DUAL_DEV
|
||||
bool "Enable cnss2 support dual wlan card"
|
||||
depends on CNSS2 && !CNSS_ASYNC
|
||||
help
|
||||
This enables the changes from cnss2 platform driver to support dual
|
||||
wlan card attach. Now just supports QCA6390 chip and does not support
|
||||
asynchronous probe.
|
||||
|
||||
config CNSS2_CONDITIONAL_POWEROFF
|
||||
bool "Enable/Disable conditional bus suspend and device power off"
|
||||
depends on CNSS2
|
||||
|
41
cnss2/bus.c
41
cnss2/bus.c
@@ -48,6 +48,7 @@ enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv)
|
||||
case QCA6174_DEVICE_ID:
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -635,6 +636,46 @@ int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
|
||||
}
|
||||
}
|
||||
|
||||
int cnss_bus_set_therm_cdev_state(struct cnss_plat_data *plat_priv,
|
||||
unsigned long thermal_state,
|
||||
int tcdev_id)
|
||||
{
|
||||
if (!plat_priv)
|
||||
return -ENODEV;
|
||||
|
||||
switch (plat_priv->bus_type) {
|
||||
case CNSS_BUS_PCI:
|
||||
return cnss_pci_set_therm_cdev_state(plat_priv->bus_priv,
|
||||
thermal_state,
|
||||
tcdev_id);
|
||||
default:
|
||||
cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv,
|
||||
char *msi_name,
|
||||
int *num_vectors,
|
||||
u32 *user_base_data,
|
||||
u32 *base_vector)
|
||||
{
|
||||
if (!plat_priv)
|
||||
return -ENODEV;
|
||||
|
||||
switch (plat_priv->bus_type) {
|
||||
case CNSS_BUS_PCI:
|
||||
return cnss_pci_get_user_msi_assignment(plat_priv->bus_priv,
|
||||
msi_name,
|
||||
num_vectors,
|
||||
user_base_data,
|
||||
base_vector);
|
||||
default:
|
||||
cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
|
||||
void cnss_bus_disable_mhi_satellite_cfg(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#define QCA6390_DEVICE_ID 0x1101
|
||||
#define QCA6490_VENDOR_ID 0x17CB
|
||||
#define QCA6490_DEVICE_ID 0x1103
|
||||
#define QCN7605_VENDOR_ID 0x17CB
|
||||
#define QCN7605_DEVICE_ID 0x1102
|
||||
#define KIWI_VENDOR_ID 0x17CB
|
||||
#define KIWI_DEVICE_ID 0x1107
|
||||
@@ -77,4 +78,12 @@ bool cnss_bus_is_smmu_s1_enabled(struct cnss_plat_data *plat_priv);
|
||||
int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
|
||||
unsigned int time_sync_period);
|
||||
void cnss_bus_disable_mhi_satellite_cfg(struct cnss_plat_data *plat_priv);
|
||||
int cnss_bus_set_therm_cdev_state(struct cnss_plat_data *plat_priv,
|
||||
unsigned long thermal_state,
|
||||
int tcdev_id);
|
||||
int cnss_bus_get_msi_assignment(struct cnss_plat_data *plat_priv,
|
||||
char *msi_name,
|
||||
int *num_vectors,
|
||||
u32 *user_base_data,
|
||||
u32 *base_vector);
|
||||
#endif /* _CNSS_BUS_H */
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
|
||||
/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */
|
||||
/* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
|
||||
|
||||
|
||||
#include <linux/err.h>
|
||||
@@ -576,6 +576,8 @@ static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
|
||||
buf[len] = '\0';
|
||||
cmd = buf;
|
||||
|
||||
cnss_pr_dbg("Received runtime_pm debug command: %s\n", cmd);
|
||||
|
||||
if (sysfs_streq(cmd, "usage_count")) {
|
||||
cnss_pci_pm_runtime_show_usage_count(pci_priv);
|
||||
} else if (sysfs_streq(cmd, "request_resume")) {
|
||||
@@ -944,8 +946,15 @@ int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *root_dentry;
|
||||
char name[CNSS_FS_NAME_SIZE];
|
||||
|
||||
root_dentry = debugfs_create_dir("cnss", 0);
|
||||
if (cnss_is_dual_wlan_enabled())
|
||||
snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME "_%d",
|
||||
plat_priv->plat_idx);
|
||||
else
|
||||
snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
|
||||
|
||||
root_dentry = debugfs_create_dir(name, 0);
|
||||
if (IS_ERR(root_dentry)) {
|
||||
ret = PTR_ERR(root_dentry);
|
||||
cnss_pr_err("Unable to create debugfs %d\n", ret);
|
||||
|
473
cnss2/main.c
473
cnss2/main.c
@@ -17,6 +17,7 @@
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0))
|
||||
#include <linux/panic_notifier.h>
|
||||
@@ -88,7 +89,13 @@ enum cnss_recovery_type {
|
||||
CNSS_PCSS_RECOVERY = 0x2,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
#define CNSS_MAX_DEV_NUM 2
|
||||
static struct cnss_plat_data *plat_env[CNSS_MAX_DEV_NUM];
|
||||
static int plat_env_count;
|
||||
#else
|
||||
static struct cnss_plat_data *plat_env;
|
||||
#endif
|
||||
|
||||
static bool cnss_allow_driver_loading;
|
||||
|
||||
@@ -111,22 +118,174 @@ struct cnss_driver_event {
|
||||
void *data;
|
||||
};
|
||||
|
||||
bool cnss_check_driver_loading_allowed(void)
|
||||
{
|
||||
return cnss_allow_driver_loading;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
static void cnss_set_plat_priv(struct platform_device *plat_dev,
|
||||
struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
cnss_pr_dbg("Set plat_priv at %d", plat_env_count);
|
||||
if (plat_priv) {
|
||||
plat_priv->plat_idx = plat_env_count;
|
||||
plat_env[plat_priv->plat_idx] = plat_priv;
|
||||
plat_env_count++;
|
||||
}
|
||||
}
|
||||
|
||||
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
|
||||
*plat_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!plat_dev)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < plat_env_count; i++) {
|
||||
if (plat_env[i]->plat_dev == plat_dev)
|
||||
return plat_env[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
cnss_pr_dbg("Clear plat_priv at %d", plat_priv->plat_idx);
|
||||
plat_env[plat_priv->plat_idx] = NULL;
|
||||
plat_env_count--;
|
||||
}
|
||||
|
||||
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
|
||||
"wlan_%d", plat_priv->plat_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cnss_plat_env_available(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (plat_env_count >= CNSS_MAX_DEV_NUM) {
|
||||
cnss_pr_err("ERROR: No space to store plat_priv\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cnss_get_plat_env_count(void)
|
||||
{
|
||||
return plat_env_count;
|
||||
}
|
||||
|
||||
struct cnss_plat_data *cnss_get_plat_env(int index)
|
||||
{
|
||||
return plat_env[index];
|
||||
}
|
||||
|
||||
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < plat_env_count; i++) {
|
||||
if (plat_env[i]->rc_num == rc_num)
|
||||
return plat_env[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
cnss_get_qrtr_node_id(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
return of_property_read_u32(plat_priv->dev_node,
|
||||
"qcom,qrtr_node_id", &plat_priv->qrtr_node_id);
|
||||
}
|
||||
|
||||
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = cnss_get_qrtr_node_id(plat_priv);
|
||||
if (ret) {
|
||||
cnss_pr_warn("Failed to find qrtr_node_id err=%d\n", ret);
|
||||
plat_priv->qrtr_node_id = 0;
|
||||
plat_priv->wlfw_service_instance_id = 0;
|
||||
} else {
|
||||
plat_priv->wlfw_service_instance_id = plat_priv->qrtr_node_id +
|
||||
QRTR_NODE_FW_ID_BASE;
|
||||
cnss_pr_dbg("service_instance_id=0x%x\n",
|
||||
plat_priv->wlfw_service_instance_id);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
cnss_get_pld_bus_ops_name(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
return of_property_read_string(plat_priv->plat_dev->dev.of_node,
|
||||
"qcom,pld_bus_ops_name",
|
||||
&plat_priv->pld_bus_ops_name);
|
||||
}
|
||||
|
||||
#else
|
||||
static void cnss_set_plat_priv(struct platform_device *plat_dev,
|
||||
struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
plat_env = plat_priv;
|
||||
}
|
||||
|
||||
bool cnss_check_driver_loading_allowed(void)
|
||||
{
|
||||
return cnss_allow_driver_loading;
|
||||
}
|
||||
|
||||
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
|
||||
{
|
||||
return plat_env;
|
||||
}
|
||||
|
||||
static void cnss_clear_plat_priv(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
plat_env = NULL;
|
||||
}
|
||||
|
||||
static int cnss_set_device_name(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
snprintf(plat_priv->device_name, sizeof(plat_priv->device_name),
|
||||
"wlan");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cnss_plat_env_available(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num)
|
||||
{
|
||||
return cnss_bus_dev_to_plat_priv(NULL);
|
||||
}
|
||||
|
||||
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
cnss_get_pld_bus_ops_name(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
cnss_get_rc_num(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
return of_property_read_u32(plat_priv->plat_dev->dev.of_node,
|
||||
"qcom,wlan-rc-num", &plat_priv->rc_num);
|
||||
}
|
||||
|
||||
bool cnss_is_dual_wlan_enabled(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_CNSS_SUPPORT_DUAL_DEV);
|
||||
}
|
||||
|
||||
/**
|
||||
* cnss_get_mem_seg_count - Get segment count of memory
|
||||
* @type: memory type
|
||||
@@ -436,6 +595,9 @@ int cnss_wlan_enable(struct device *dev,
|
||||
if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
|
||||
goto skip_cfg;
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
config->send_msi_ce = true;
|
||||
|
||||
ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, config, host_version);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -639,6 +801,9 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
|
||||
|
||||
cnss_wlfw_bdf_dnld_send_sync(plat_priv, CNSS_BDF_REGDB);
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
plat_priv->ctrl_params.bdf_type = CNSS_BDF_BIN;
|
||||
|
||||
cnss_wlfw_ini_file_send_sync(plat_priv, WLFW_CONN_ROAM_INI_V01);
|
||||
|
||||
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv,
|
||||
@@ -646,6 +811,9 @@ static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
return 0;
|
||||
|
||||
ret = cnss_bus_load_m3(plat_priv);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -1212,8 +1380,6 @@ EXPORT_SYMBOL(cnss_idle_restart);
|
||||
int cnss_idle_shutdown(struct device *dev)
|
||||
{
|
||||
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
|
||||
unsigned int timeout;
|
||||
int ret;
|
||||
|
||||
if (!plat_priv) {
|
||||
cnss_pr_err("plat_priv is NULL\n");
|
||||
@@ -1227,21 +1393,12 @@ int cnss_idle_shutdown(struct device *dev)
|
||||
|
||||
cnss_pr_dbg("Doing idle shutdown\n");
|
||||
|
||||
if (!test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
|
||||
!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
|
||||
goto skip_wait;
|
||||
|
||||
reinit_completion(&plat_priv->recovery_complete);
|
||||
timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_RECOVERY);
|
||||
ret = wait_for_completion_timeout(&plat_priv->recovery_complete,
|
||||
msecs_to_jiffies(timeout));
|
||||
if (!ret) {
|
||||
cnss_pr_err("Timeout (%ums) waiting for recovery to complete\n",
|
||||
timeout);
|
||||
CNSS_ASSERT(0);
|
||||
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
|
||||
test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
|
||||
cnss_pr_dbg("Recovery in progress. Ignore IDLE Shutdown\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
skip_wait:
|
||||
return cnss_driver_event_post(plat_priv,
|
||||
CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
|
||||
CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
|
||||
@@ -2187,8 +2344,14 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
|
||||
cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
|
||||
cnss_bus_free_qdss_mem(plat_priv);
|
||||
cnss_release_antenna_sharing(plat_priv);
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
goto skip_shutdown;
|
||||
|
||||
cnss_bus_dev_shutdown(plat_priv);
|
||||
msleep(POWER_RESET_MIN_DELAY_MS);
|
||||
|
||||
skip_shutdown:
|
||||
complete(&plat_priv->cal_complete);
|
||||
clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
|
||||
set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state);
|
||||
@@ -2482,7 +2645,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv)
|
||||
|
||||
subsys_info = &plat_priv->subsys_info;
|
||||
|
||||
subsys_info->subsys_desc.name = "wlan";
|
||||
subsys_info->subsys_desc.name = plat_priv->device_name;
|
||||
subsys_info->subsys_desc.owner = THIS_MODULE;
|
||||
subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
|
||||
subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
|
||||
@@ -3225,6 +3388,7 @@ int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -3247,6 +3411,7 @@ void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -3861,8 +4026,21 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
struct device *dev = &plat_priv->plat_dev->dev;
|
||||
int ret;
|
||||
char cnss_name[CNSS_FS_NAME_SIZE];
|
||||
char shutdown_name[32];
|
||||
|
||||
ret = sysfs_create_link(kernel_kobj, &dev->kobj, "cnss");
|
||||
if (cnss_is_dual_wlan_enabled()) {
|
||||
snprintf(cnss_name, CNSS_FS_NAME_SIZE,
|
||||
CNSS_FS_NAME "_%d", plat_priv->plat_idx);
|
||||
snprintf(shutdown_name, sizeof(shutdown_name),
|
||||
"shutdown_wlan_%d", plat_priv->plat_idx);
|
||||
} else {
|
||||
snprintf(cnss_name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
|
||||
snprintf(shutdown_name, sizeof(shutdown_name),
|
||||
"shutdown_wlan");
|
||||
}
|
||||
|
||||
ret = sysfs_create_link(kernel_kobj, &dev->kobj, cnss_name);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to create cnss link, err = %d\n",
|
||||
ret);
|
||||
@@ -3870,7 +4048,7 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
|
||||
}
|
||||
|
||||
/* This is only for backward compatibility. */
|
||||
ret = sysfs_create_link(kernel_kobj, &dev->kobj, "shutdown_wlan");
|
||||
ret = sysfs_create_link(kernel_kobj, &dev->kobj, shutdown_name);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to create shutdown_wlan link, err = %d\n",
|
||||
ret);
|
||||
@@ -3880,15 +4058,29 @@ static int cnss_create_sysfs_link(struct cnss_plat_data *plat_priv)
|
||||
return 0;
|
||||
|
||||
rm_cnss_link:
|
||||
sysfs_remove_link(kernel_kobj, "cnss");
|
||||
sysfs_remove_link(kernel_kobj, cnss_name);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cnss_remove_sysfs_link(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
sysfs_remove_link(kernel_kobj, "shutdown_wlan");
|
||||
sysfs_remove_link(kernel_kobj, "cnss");
|
||||
char cnss_name[CNSS_FS_NAME_SIZE];
|
||||
char shutdown_name[32];
|
||||
|
||||
if (cnss_is_dual_wlan_enabled()) {
|
||||
snprintf(cnss_name, CNSS_FS_NAME_SIZE,
|
||||
CNSS_FS_NAME "_%d", plat_priv->plat_idx);
|
||||
snprintf(shutdown_name, sizeof(shutdown_name),
|
||||
"shutdown_wlan_%d", plat_priv->plat_idx);
|
||||
} else {
|
||||
snprintf(cnss_name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
|
||||
snprintf(shutdown_name, sizeof(shutdown_name),
|
||||
"shutdown_wlan");
|
||||
}
|
||||
|
||||
sysfs_remove_link(kernel_kobj, shutdown_name);
|
||||
sysfs_remove_link(kernel_kobj, cnss_name);
|
||||
}
|
||||
|
||||
static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
|
||||
@@ -4095,6 +4287,7 @@ static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
|
||||
wakeup_source_unregister(plat_priv->recovery_ws);
|
||||
cnss_deinit_sol_gpio(plat_priv);
|
||||
kfree(plat_priv->sram_dump);
|
||||
kfree(plat_priv->on_chip_pmic_board_ids);
|
||||
}
|
||||
|
||||
static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
|
||||
@@ -4358,6 +4551,195 @@ int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg)
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_set_wfc_mode);
|
||||
|
||||
static int cnss_tcdev_get_max_state(struct thermal_cooling_device *tcdev,
|
||||
unsigned long *thermal_state)
|
||||
{
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
|
||||
if (!tcdev || !tcdev->devdata) {
|
||||
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cnss_tcdev = tcdev->devdata;
|
||||
*thermal_state = cnss_tcdev->max_thermal_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cnss_tcdev_get_cur_state(struct thermal_cooling_device *tcdev,
|
||||
unsigned long *thermal_state)
|
||||
{
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
|
||||
if (!tcdev || !tcdev->devdata) {
|
||||
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cnss_tcdev = tcdev->devdata;
|
||||
*thermal_state = cnss_tcdev->curr_thermal_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cnss_tcdev_set_cur_state(struct thermal_cooling_device *tcdev,
|
||||
unsigned long thermal_state)
|
||||
{
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
|
||||
int ret = 0;
|
||||
|
||||
if (!tcdev || !tcdev->devdata) {
|
||||
cnss_pr_err("tcdev or tcdev->devdata is null!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cnss_tcdev = tcdev->devdata;
|
||||
|
||||
if (thermal_state > cnss_tcdev->max_thermal_state)
|
||||
return -EINVAL;
|
||||
|
||||
cnss_pr_vdbg("Cooling device set current state: %ld,for cdev id %d",
|
||||
thermal_state, cnss_tcdev->tcdev_id);
|
||||
|
||||
mutex_lock(&plat_priv->tcdev_lock);
|
||||
ret = cnss_bus_set_therm_cdev_state(plat_priv,
|
||||
thermal_state,
|
||||
cnss_tcdev->tcdev_id);
|
||||
if (!ret)
|
||||
cnss_tcdev->curr_thermal_state = thermal_state;
|
||||
mutex_unlock(&plat_priv->tcdev_lock);
|
||||
if (ret) {
|
||||
cnss_pr_err("Setting Current Thermal State Failed: %d,for cdev id %d",
|
||||
ret, cnss_tcdev->tcdev_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_cooling_device_ops cnss_cooling_ops = {
|
||||
.get_max_state = cnss_tcdev_get_max_state,
|
||||
.get_cur_state = cnss_tcdev_get_cur_state,
|
||||
.set_cur_state = cnss_tcdev_set_cur_state,
|
||||
};
|
||||
|
||||
int cnss_thermal_cdev_register(struct device *dev, unsigned long max_state,
|
||||
int tcdev_id)
|
||||
{
|
||||
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
char cdev_node_name[THERMAL_NAME_LENGTH] = "";
|
||||
struct device_node *dev_node;
|
||||
int ret = 0;
|
||||
|
||||
if (!priv) {
|
||||
cnss_pr_err("Platform driver is not initialized!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cnss_tcdev = kzalloc(sizeof(*cnss_tcdev), GFP_KERNEL);
|
||||
if (!cnss_tcdev) {
|
||||
cnss_pr_err("Failed to allocate cnss_tcdev object!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cnss_tcdev->tcdev_id = tcdev_id;
|
||||
cnss_tcdev->max_thermal_state = max_state;
|
||||
|
||||
snprintf(cdev_node_name, THERMAL_NAME_LENGTH,
|
||||
"qcom,cnss_cdev%d", tcdev_id);
|
||||
|
||||
dev_node = of_find_node_by_name(NULL, cdev_node_name);
|
||||
if (!dev_node) {
|
||||
cnss_pr_err("Failed to get cooling device node\n");
|
||||
kfree(cnss_tcdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cnss_pr_dbg("tcdev node->name=%s\n", dev_node->name);
|
||||
|
||||
if (of_find_property(dev_node, "#cooling-cells", NULL)) {
|
||||
cnss_tcdev->tcdev = thermal_of_cooling_device_register(dev_node,
|
||||
cdev_node_name,
|
||||
cnss_tcdev,
|
||||
&cnss_cooling_ops);
|
||||
if (IS_ERR_OR_NULL(cnss_tcdev->tcdev)) {
|
||||
ret = PTR_ERR(cnss_tcdev->tcdev);
|
||||
cnss_pr_err("Cooling device register failed: %d, for cdev id %d\n",
|
||||
ret, cnss_tcdev->tcdev_id);
|
||||
kfree(cnss_tcdev);
|
||||
} else {
|
||||
cnss_pr_dbg("Cooling device registered for cdev id %d",
|
||||
cnss_tcdev->tcdev_id);
|
||||
mutex_lock(&priv->tcdev_lock);
|
||||
list_add(&cnss_tcdev->tcdev_list,
|
||||
&priv->cnss_tcdev_list);
|
||||
mutex_unlock(&priv->tcdev_lock);
|
||||
}
|
||||
} else {
|
||||
cnss_pr_dbg("Cooling device registration not supported");
|
||||
kfree(cnss_tcdev);
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_thermal_cdev_register);
|
||||
|
||||
void cnss_thermal_cdev_unregister(struct device *dev, int tcdev_id)
|
||||
{
|
||||
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
|
||||
if (!priv) {
|
||||
cnss_pr_err("Platform driver is not initialized!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->tcdev_lock);
|
||||
while (!list_empty(&priv->cnss_tcdev_list)) {
|
||||
cnss_tcdev = list_first_entry(&priv->cnss_tcdev_list,
|
||||
struct cnss_thermal_cdev,
|
||||
tcdev_list);
|
||||
thermal_cooling_device_unregister(cnss_tcdev->tcdev);
|
||||
list_del(&cnss_tcdev->tcdev_list);
|
||||
kfree(cnss_tcdev);
|
||||
}
|
||||
mutex_unlock(&priv->tcdev_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_thermal_cdev_unregister);
|
||||
|
||||
int cnss_get_curr_therm_cdev_state(struct device *dev,
|
||||
unsigned long *thermal_state,
|
||||
int tcdev_id)
|
||||
{
|
||||
struct cnss_plat_data *priv = cnss_get_plat_priv(NULL);
|
||||
struct cnss_thermal_cdev *cnss_tcdev = NULL;
|
||||
|
||||
if (!priv) {
|
||||
cnss_pr_err("Platform driver is not initialized!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->tcdev_lock);
|
||||
list_for_each_entry(cnss_tcdev, &priv->cnss_tcdev_list, tcdev_list) {
|
||||
if (cnss_tcdev->tcdev_id != tcdev_id)
|
||||
continue;
|
||||
|
||||
*thermal_state = cnss_tcdev->curr_thermal_state;
|
||||
mutex_unlock(&priv->tcdev_lock);
|
||||
cnss_pr_dbg("Cooling device current state: %ld, for cdev id %d",
|
||||
cnss_tcdev->curr_thermal_state, tcdev_id);
|
||||
return 0;
|
||||
}
|
||||
mutex_unlock(&priv->tcdev_lock);
|
||||
cnss_pr_dbg("Cooling device ID not found: %d", tcdev_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_get_curr_therm_cdev_state);
|
||||
|
||||
static int cnss_probe(struct platform_device *plat_dev)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -4371,6 +4753,10 @@ static int cnss_probe(struct platform_device *plat_dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = cnss_plat_env_available();
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
|
||||
if (!of_id || !of_id->data) {
|
||||
cnss_pr_err("Failed to find of match device!\n");
|
||||
@@ -4403,10 +4789,23 @@ static int cnss_probe(struct platform_device *plat_dev)
|
||||
goto reset_plat_dev;
|
||||
}
|
||||
|
||||
ret = cnss_get_pld_bus_ops_name(plat_priv);
|
||||
if (ret)
|
||||
cnss_pr_err("Failed to find bus ops name, err = %d\n",
|
||||
ret);
|
||||
|
||||
ret = cnss_get_rc_num(plat_priv);
|
||||
|
||||
if (ret)
|
||||
cnss_pr_err("Failed to find PCIe RC number, err = %d\n", ret);
|
||||
|
||||
cnss_pr_dbg("rc_num=%d\n", plat_priv->rc_num);
|
||||
|
||||
plat_priv->bus_type = cnss_get_bus_type(plat_priv);
|
||||
plat_priv->use_nv_mac = cnss_use_nv_mac(plat_priv);
|
||||
plat_priv->driver_mode = CNSS_DRIVER_MODE_MAX;
|
||||
cnss_set_plat_priv(plat_dev, plat_priv);
|
||||
cnss_set_device_name(plat_priv);
|
||||
platform_set_drvdata(plat_dev, plat_priv);
|
||||
INIT_LIST_HEAD(&plat_priv->vreg_list);
|
||||
INIT_LIST_HEAD(&plat_priv->clk_list);
|
||||
@@ -4439,13 +4838,9 @@ static int cnss_probe(struct platform_device *plat_dev)
|
||||
if (ret)
|
||||
goto remove_sysfs;
|
||||
|
||||
ret = cnss_qmi_init(plat_priv);
|
||||
if (ret)
|
||||
goto deinit_event_work;
|
||||
|
||||
ret = cnss_dms_init(plat_priv);
|
||||
if (ret)
|
||||
goto deinit_qmi;
|
||||
goto deinit_event_work;
|
||||
|
||||
ret = cnss_debugfs_create(plat_priv);
|
||||
if (ret)
|
||||
@@ -4472,9 +4867,8 @@ static int cnss_probe(struct platform_device *plat_dev)
|
||||
cnss_register_coex_service(plat_priv);
|
||||
cnss_register_ims_service(plat_priv);
|
||||
|
||||
ret = cnss_genl_init();
|
||||
if (ret < 0)
|
||||
cnss_pr_err("CNSS genl init failed %d\n", ret);
|
||||
mutex_init(&plat_priv->tcdev_lock);
|
||||
INIT_LIST_HEAD(&plat_priv->cnss_tcdev_list);
|
||||
|
||||
cnss_pr_info("Platform driver probed successfully.\n");
|
||||
|
||||
@@ -4486,8 +4880,6 @@ destroy_debugfs:
|
||||
cnss_debugfs_destroy(plat_priv);
|
||||
deinit_dms:
|
||||
cnss_dms_deinit(plat_priv);
|
||||
deinit_qmi:
|
||||
cnss_qmi_deinit(plat_priv);
|
||||
deinit_event_work:
|
||||
cnss_event_work_deinit(plat_priv);
|
||||
remove_sysfs:
|
||||
@@ -4501,7 +4893,7 @@ free_res:
|
||||
reset_ctx:
|
||||
platform_set_drvdata(plat_dev, NULL);
|
||||
reset_plat_dev:
|
||||
cnss_set_plat_priv(plat_dev, NULL);
|
||||
cnss_clear_plat_priv(plat_priv);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -4530,7 +4922,7 @@ static int cnss_remove(struct platform_device *plat_dev)
|
||||
mbox_free_channel(plat_priv->mbox_chan);
|
||||
|
||||
platform_set_drvdata(plat_dev, NULL);
|
||||
plat_env = NULL;
|
||||
cnss_clear_plat_priv(plat_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4599,11 +4991,16 @@ static int __init cnss_initialize(void)
|
||||
if (ret)
|
||||
cnss_debug_deinit();
|
||||
|
||||
ret = cnss_genl_init();
|
||||
if (ret < 0)
|
||||
cnss_pr_err("CNSS genl init failed %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit cnss_exit(void)
|
||||
{
|
||||
cnss_genl_exit();
|
||||
platform_driver_unregister(&cnss_platform_driver);
|
||||
cnss_debug_deinit();
|
||||
}
|
||||
|
34
cnss2/main.h
34
cnss2/main.h
@@ -55,7 +55,17 @@
|
||||
#define CNSS_RAMDUMP_VERSION 0
|
||||
#define MAX_FIRMWARE_NAME_LEN 40
|
||||
#define FW_V2_NUMBER 2
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
#define POWER_ON_RETRY_MAX_TIMES 2
|
||||
#else
|
||||
#define POWER_ON_RETRY_MAX_TIMES 4
|
||||
#endif
|
||||
#define POWER_ON_RETRY_DELAY_MS 500
|
||||
#define CNSS_FS_NAME "cnss"
|
||||
#define CNSS_FS_NAME_SIZE 15
|
||||
#define CNSS_DEVICE_NAME_SIZE 16
|
||||
#define QRTR_NODE_FW_ID_BASE 7
|
||||
|
||||
#define POWER_ON_RETRY_DELAY_MS 500
|
||||
#define WLFW_MAX_HANG_EVENT_DATA_SIZE 384
|
||||
|
||||
@@ -458,6 +468,15 @@ struct cnss_sol_gpio {
|
||||
int host_sol_gpio;
|
||||
};
|
||||
|
||||
struct cnss_thermal_cdev {
|
||||
struct list_head tcdev_list;
|
||||
int tcdev_id;
|
||||
unsigned long curr_thermal_state;
|
||||
unsigned long max_thermal_state;
|
||||
struct device_node *dev_node;
|
||||
struct thermal_cooling_device *tcdev;
|
||||
};
|
||||
|
||||
struct cnss_plat_data {
|
||||
struct platform_device *plat_dev;
|
||||
void *bus_priv;
|
||||
@@ -490,6 +509,8 @@ struct cnss_plat_data {
|
||||
u8 hds_enabled;
|
||||
unsigned long driver_state;
|
||||
struct list_head event_list;
|
||||
struct list_head cnss_tcdev_list;
|
||||
struct mutex tcdev_lock; /* mutex for cooling devices list access */
|
||||
spinlock_t event_lock; /* spinlock for driver work event handling */
|
||||
struct work_struct event_work;
|
||||
struct workqueue_struct *event_wq;
|
||||
@@ -578,6 +599,14 @@ struct cnss_plat_data {
|
||||
uint32_t num_shadow_regs_v3;
|
||||
bool sec_peri_feature_disable;
|
||||
struct device_node *dev_node;
|
||||
char device_name[CNSS_DEVICE_NAME_SIZE];
|
||||
u32 plat_idx;
|
||||
bool enumerate_done;
|
||||
int qrtr_node_id;
|
||||
unsigned int wlfw_service_instance_id;
|
||||
const char *pld_bus_ops_name;
|
||||
u32 on_chip_pmic_devices_count;
|
||||
u32 *on_chip_pmic_board_ids;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_QCOM)
|
||||
@@ -605,6 +634,11 @@ int cnss_wlan_hw_enable(void);
|
||||
struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
|
||||
void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv);
|
||||
void cnss_pm_relax(struct cnss_plat_data *plat_priv);
|
||||
struct cnss_plat_data *cnss_get_plat_priv_by_rc_num(int rc_num);
|
||||
int cnss_get_plat_env_count(void);
|
||||
struct cnss_plat_data *cnss_get_plat_env(int index);
|
||||
void cnss_get_qrtr_info(struct cnss_plat_data *plat_priv);
|
||||
bool cnss_is_dual_wlan_enabled(void);
|
||||
int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
|
||||
enum cnss_driver_event_type type,
|
||||
u32 flags, void *data);
|
||||
|
511
cnss2/pci.c
511
cnss2/pci.c
@@ -35,13 +35,14 @@
|
||||
|
||||
#define PCI_DMA_MASK_32_BIT DMA_BIT_MASK(32)
|
||||
#define PCI_DMA_MASK_36_BIT DMA_BIT_MASK(36)
|
||||
#define PCI_DMA_MASK_64_BIT DMA_BIT_MASK(64)
|
||||
#define PCI_DMA_MASK_64_BIT ~0ULL
|
||||
|
||||
#define MHI_NODE_NAME "qcom,mhi"
|
||||
#define MHI_MSI_NAME "MHI"
|
||||
|
||||
#define QCA6390_PATH_PREFIX "qca6390/"
|
||||
#define QCA6490_PATH_PREFIX "qca6490/"
|
||||
#define QCN7605_PATH_PREFIX "qcn7605/"
|
||||
#define KIWI_PATH_PREFIX "kiwi/"
|
||||
#define MANGO_PATH_PREFIX "mango/"
|
||||
#define PEACH_PATH_PREFIX "peach/"
|
||||
@@ -68,6 +69,8 @@
|
||||
#define CNSS_256KB_SIZE 0x40000
|
||||
#define DEVICE_RDDM_COOKIE 0xCAFECACE
|
||||
|
||||
static bool cnss_driver_registered;
|
||||
|
||||
static DEFINE_SPINLOCK(pci_link_down_lock);
|
||||
static DEFINE_SPINLOCK(pci_reg_window_lock);
|
||||
static DEFINE_SPINLOCK(time_sync_lock);
|
||||
@@ -82,6 +85,8 @@ static DEFINE_SPINLOCK(time_sync_lock);
|
||||
#define FORCE_WAKE_DELAY_MAX_US 6000
|
||||
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
|
||||
|
||||
#define REG_RETRY_MAX_TIMES 3
|
||||
|
||||
#define MHI_SUSPEND_RETRY_MAX_TIMES 3
|
||||
#define MHI_SUSPEND_RETRY_DELAY_US 5000
|
||||
|
||||
@@ -244,6 +249,93 @@ static const struct mhi_channel_config cnss_mhi_channels[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config cnss_mhi_channels_genoa[] = {
|
||||
{
|
||||
.num = 0,
|
||||
.name = "LOOPBACK",
|
||||
.num_elements = 32,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = false,
|
||||
},
|
||||
{
|
||||
.num = 1,
|
||||
.name = "LOOPBACK",
|
||||
.num_elements = 32,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = false,
|
||||
},
|
||||
{
|
||||
.num = 4,
|
||||
.name = "DIAG",
|
||||
.num_elements = 64,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = false,
|
||||
},
|
||||
{
|
||||
.num = 5,
|
||||
.name = "DIAG",
|
||||
.num_elements = 64,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = false,
|
||||
},
|
||||
{
|
||||
.num = 16,
|
||||
.name = "IPCR",
|
||||
.num_elements = 64,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_TO_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = false,
|
||||
},
|
||||
{
|
||||
.num = 17,
|
||||
.name = "IPCR",
|
||||
.num_elements = 64,
|
||||
.event_ring = 1,
|
||||
.dir = DMA_FROM_DEVICE,
|
||||
.ee_mask = 0x4,
|
||||
.pollcfg = 0,
|
||||
.doorbell = MHI_DB_BRST_DISABLE,
|
||||
.lpm_notify = false,
|
||||
.offload_channel = false,
|
||||
.doorbell_mode_switch = false,
|
||||
.auto_queue = true,
|
||||
},
|
||||
};
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
|
||||
static struct mhi_event_config cnss_mhi_events[] = {
|
||||
#else
|
||||
@@ -322,6 +414,20 @@ static const struct mhi_controller_config cnss_mhi_config_default = {
|
||||
.m2_no_db = true,
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config cnss_mhi_config_genoa = {
|
||||
.max_channels = 32,
|
||||
.timeout_ms = 10000,
|
||||
.use_bounce_buf = false,
|
||||
.buf_len = 0x8000,
|
||||
.num_channels = ARRAY_SIZE(cnss_mhi_channels_genoa),
|
||||
.ch_cfg = cnss_mhi_channels_genoa,
|
||||
.num_events = ARRAY_SIZE(cnss_mhi_events) -
|
||||
CNSS_MHI_SATELLITE_EVT_COUNT,
|
||||
.event_cfg = cnss_mhi_events,
|
||||
.m2_no_db = true,
|
||||
.bhie_offset = 0x0324,
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config cnss_mhi_config_no_satellite = {
|
||||
.max_channels = 32,
|
||||
.timeout_ms = 10000,
|
||||
@@ -667,6 +773,9 @@ static struct cnss_print_optimize print_optimize;
|
||||
#define SYSPM_REG_SIZE ARRAY_SIZE(syspm_reg_access_seq)
|
||||
|
||||
static int cnss_pci_update_fw_name(struct cnss_pci_data *pci_priv);
|
||||
static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev);
|
||||
static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev);
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
|
||||
static void cnss_mhi_debug_reg_dump(struct cnss_pci_data *pci_priv)
|
||||
@@ -826,6 +935,9 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset)
|
||||
QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET);
|
||||
}
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
window_enable = QCN7605_WINDOW_ENABLE_BIT | window;
|
||||
|
||||
if (window != pci_priv->remap_window) {
|
||||
pci_priv->remap_window = window;
|
||||
cnss_pr_dbg("Config PCIe remap window register to 0x%x\n",
|
||||
@@ -1809,6 +1921,18 @@ static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv,
|
||||
}
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
|
||||
static int cnss_mhi_pm_force_resume(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
return mhi_pm_resume_force(pci_priv->mhi_ctrl);
|
||||
}
|
||||
#else
|
||||
static int cnss_mhi_pm_force_resume(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
return mhi_pm_resume(pci_priv->mhi_ctrl);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
|
||||
enum cnss_mhi_state mhi_state)
|
||||
{
|
||||
@@ -1881,7 +2005,10 @@ retry_mhi_suspend:
|
||||
ret = cnss_mhi_pm_fast_resume(pci_priv, true);
|
||||
cnss_pci_allow_l1(&pci_priv->pci_dev->dev);
|
||||
} else {
|
||||
ret = mhi_pm_resume(pci_priv->mhi_ctrl);
|
||||
if (pci_priv->device_id == QCA6390_DEVICE_ID)
|
||||
ret = cnss_mhi_pm_force_resume(pci_priv);
|
||||
else
|
||||
ret = mhi_pm_resume(pci_priv->mhi_ctrl);
|
||||
}
|
||||
mutex_unlock(&pci_priv->mhi_ctrl->pm_mutex);
|
||||
break;
|
||||
@@ -1933,11 +2060,158 @@ static int cnss_pci_config_msi_data(struct cnss_pci_data *pci_priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
#define PLC_PCIE_NAME_LEN 14
|
||||
|
||||
static struct cnss_plat_data *
|
||||
cnss_get_plat_priv_by_driver_ops(struct cnss_wlan_driver *driver_ops)
|
||||
{
|
||||
int plat_env_count = cnss_get_plat_env_count();
|
||||
struct cnss_plat_data *plat_env;
|
||||
struct cnss_pci_data *pci_priv;
|
||||
int i = 0;
|
||||
|
||||
if (!driver_ops) {
|
||||
cnss_pr_err("No cnss driver\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < plat_env_count; i++) {
|
||||
plat_env = cnss_get_plat_env(i);
|
||||
if (!plat_env)
|
||||
continue;
|
||||
if (driver_ops->name && plat_env->pld_bus_ops_name) {
|
||||
/* driver_ops->name = PLD_PCIE_OPS_NAME
|
||||
* #ifdef MULTI_IF_NAME
|
||||
* #define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
|
||||
* #else
|
||||
* #define PLD_PCIE_OPS_NAME "pld_pcie"
|
||||
* #endif
|
||||
*/
|
||||
if (memcmp(driver_ops->name,
|
||||
plat_env->pld_bus_ops_name,
|
||||
PLC_PCIE_NAME_LEN) == 0)
|
||||
return plat_env;
|
||||
}
|
||||
}
|
||||
|
||||
cnss_pr_err("Invalid cnss driver name from ko %s\n", driver_ops->name);
|
||||
/* in the dual wlan card case, the pld_bus_ops_name from dts
|
||||
* and driver_ops-> name from ko should match, otherwise
|
||||
* wlanhost driver don't know which plat_env it can use;
|
||||
* if doesn't find the match one, then get first available
|
||||
* instance insteadly.
|
||||
*/
|
||||
|
||||
for (i = 0; i < plat_env_count; i++) {
|
||||
plat_env = cnss_get_plat_env(i);
|
||||
|
||||
if (!plat_env)
|
||||
continue;
|
||||
|
||||
pci_priv = plat_env->bus_priv;
|
||||
if (!pci_priv) {
|
||||
cnss_pr_err("pci_priv is NULL\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (driver_ops == pci_priv->driver_ops)
|
||||
return plat_env;
|
||||
}
|
||||
/* Doesn't find the existing instance,
|
||||
* so return the fist empty instance
|
||||
*/
|
||||
for (i = 0; i < plat_env_count; i++) {
|
||||
plat_env = cnss_get_plat_env(i);
|
||||
|
||||
if (!plat_env)
|
||||
continue;
|
||||
pci_priv = plat_env->bus_priv;
|
||||
if (!pci_priv) {
|
||||
cnss_pr_err("pci_priv is NULL\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pci_priv->driver_ops)
|
||||
return plat_env;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cnss_pci_store_qrtr_node_id(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 scratch = QCA6390_PCIE_SOC_PCIE_REG_PCIE_SCRATCH_2_SOC_PCIE_REG;
|
||||
struct cnss_plat_data *plat_priv;
|
||||
|
||||
if (!pci_priv) {
|
||||
cnss_pr_err("pci_priv is NULL\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
plat_priv = pci_priv->plat_priv;
|
||||
/**
|
||||
* in the single wlan chipset case, plat_priv->qrtr_node_id always is 0,
|
||||
* wlan fw will use the hardcode 7 as the qrtr node id.
|
||||
* in the dual Hastings case, we will read qrtr node id
|
||||
* from device tree and pass to get plat_priv->qrtr_node_id,
|
||||
* which always is not zero. And then store this new value
|
||||
* to pcie register, wlan fw will read out this qrtr node id
|
||||
* from this register and overwrite to the hardcode one
|
||||
* while do initialization for ipc router.
|
||||
* without this change, two Hastings will use the same
|
||||
* qrtr node instance id, which will mess up qmi message
|
||||
* exchange. According to qrtr spec, every node should
|
||||
* have unique qrtr node id
|
||||
*/
|
||||
if (plat_priv->device_id == QCA6390_DEVICE_ID &&
|
||||
plat_priv->qrtr_node_id) {
|
||||
u32 val;
|
||||
|
||||
cnss_pr_dbg("write 0x%x to SCRATCH REG\n",
|
||||
plat_priv->qrtr_node_id);
|
||||
ret = cnss_pci_reg_write(pci_priv, scratch,
|
||||
plat_priv->qrtr_node_id);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
|
||||
scratch, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = cnss_pci_reg_read(pci_priv, scratch, &val);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to read SCRATCH REG");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (val != plat_priv->qrtr_node_id) {
|
||||
cnss_pr_err("qrtr node id write to register doesn't match with readout value");
|
||||
return -ERANGE;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static struct cnss_plat_data *
|
||||
cnss_get_plat_priv_by_driver_ops(struct cnss_wlan_driver *driver_ops)
|
||||
{
|
||||
return cnss_bus_dev_to_plat_priv(NULL);
|
||||
}
|
||||
|
||||
static int cnss_pci_store_qrtr_node_id(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cnss_plat_data *plat_priv;
|
||||
unsigned int timeout = 0;
|
||||
int retry = 0;
|
||||
|
||||
if (!pci_priv) {
|
||||
cnss_pr_err("pci_priv is NULL\n");
|
||||
@@ -1963,6 +2237,15 @@ int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
|
||||
else /* For perf builds the timeout is 10 (default) * 3 seconds */
|
||||
pci_priv->mhi_ctrl->timeout_ms *= 3;
|
||||
|
||||
retry:
|
||||
ret = cnss_pci_store_qrtr_node_id(pci_priv);
|
||||
if (ret) {
|
||||
if (retry++ < REG_RETRY_MAX_TIMES)
|
||||
goto retry;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start the timer to dump MHI/PBL/SBL debug data periodically */
|
||||
mod_timer(&pci_priv->boot_debug_timer,
|
||||
jiffies + msecs_to_jiffies(BOOT_DEBUG_TIMEOUT_MS));
|
||||
@@ -2312,6 +2595,25 @@ static void cnss_pci_stop_time_sync_update(struct cnss_pci_data *pci_priv)
|
||||
cancel_delayed_work_sync(&pci_priv->time_sync_work);
|
||||
}
|
||||
|
||||
int cnss_pci_set_therm_cdev_state(struct cnss_pci_data *pci_priv,
|
||||
unsigned long thermal_state,
|
||||
int tcdev_id)
|
||||
{
|
||||
if (!pci_priv) {
|
||||
cnss_pr_err("pci_priv is NULL!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!pci_priv->driver_ops || !pci_priv->driver_ops->set_therm_cdev_state) {
|
||||
cnss_pr_err("driver_ops or set_therm_cdev_state is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pci_priv->driver_ops->set_therm_cdev_state(pci_priv->pci_dev,
|
||||
thermal_state,
|
||||
tcdev_id);
|
||||
}
|
||||
|
||||
int cnss_pci_update_time_sync_period(struct cnss_pci_data *pci_priv,
|
||||
unsigned int time_sync_period)
|
||||
{
|
||||
@@ -2844,7 +3146,9 @@ static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
|
||||
test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
|
||||
del_timer(&pci_priv->dev_rddm_timer);
|
||||
cnss_pci_collect_dump_info(pci_priv, false);
|
||||
CNSS_ASSERT(0);
|
||||
|
||||
if (!plat_priv->recovery_enabled)
|
||||
CNSS_ASSERT(0);
|
||||
}
|
||||
|
||||
if (!cnss_is_device_powered_on(plat_priv)) {
|
||||
@@ -2937,6 +3241,7 @@ int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -2967,6 +3272,7 @@ int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -2997,6 +3303,7 @@ int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -3027,6 +3334,7 @@ int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -3111,7 +3419,7 @@ reg_driver:
|
||||
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
|
||||
struct cnss_plat_data *plat_priv;
|
||||
struct cnss_pci_data *pci_priv;
|
||||
const struct pci_device_id *id_table = driver_ops->id_table;
|
||||
unsigned int timeout;
|
||||
@@ -3121,6 +3429,8 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
|
||||
|
||||
if (!plat_priv) {
|
||||
cnss_pr_buf("plat_priv is not ready for register driver\n");
|
||||
return -EAGAIN;
|
||||
@@ -3216,10 +3526,11 @@ EXPORT_SYMBOL(cnss_wlan_register_driver);
|
||||
|
||||
void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
|
||||
{
|
||||
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
|
||||
struct cnss_plat_data *plat_priv;
|
||||
int ret = 0;
|
||||
unsigned int timeout;
|
||||
|
||||
plat_priv = cnss_get_plat_priv_by_driver_ops(driver_ops);
|
||||
if (!plat_priv) {
|
||||
cnss_pr_err("plat_priv is NULL\n");
|
||||
return;
|
||||
@@ -3426,7 +3737,8 @@ out:
|
||||
static int cnss_pci_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
|
||||
struct cnss_plat_data *plat_priv;
|
||||
|
||||
if (!pci_priv)
|
||||
@@ -3439,6 +3751,25 @@ static int cnss_pci_suspend(struct device *dev)
|
||||
if (!cnss_is_device_powered_on(plat_priv))
|
||||
goto out;
|
||||
|
||||
/* No mhi state bit set if only finish pcie enumeration,
|
||||
* so test_bit is not applicable to check if it is INIT state.
|
||||
*/
|
||||
if (pci_priv->mhi_state == CNSS_MHI_INIT) {
|
||||
bool suspend = cnss_should_suspend_pwroff(pci_dev);
|
||||
|
||||
/* Do PCI link suspend and power off in the LPM case
|
||||
* if chipset didn't do that after pcie enumeration.
|
||||
*/
|
||||
if (!suspend) {
|
||||
ret = cnss_suspend_pci_link(pci_priv);
|
||||
if (ret)
|
||||
cnss_pr_err("Failed to suspend PCI link, err = %d\n",
|
||||
ret);
|
||||
cnss_power_off_device(plat_priv);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks) &&
|
||||
pci_priv->drv_supported) {
|
||||
pci_priv->drv_connected_last =
|
||||
@@ -4614,6 +4945,19 @@ int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
|
||||
}
|
||||
EXPORT_SYMBOL(cnss_get_soc_info);
|
||||
|
||||
int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv,
|
||||
char *user_name,
|
||||
int *num_vectors,
|
||||
u32 *user_base_data,
|
||||
u32 *base_vector)
|
||||
{
|
||||
return cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
|
||||
user_name,
|
||||
num_vectors,
|
||||
user_base_data,
|
||||
base_vector);
|
||||
}
|
||||
|
||||
static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -4852,6 +5196,9 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
|
||||
case PEACH_DEVICE_ID:
|
||||
pci_priv->dma_bit_mask = PCI_DMA_MASK_36_BIT;
|
||||
break;
|
||||
case QCN7605_DEVICE_ID:
|
||||
pci_priv->dma_bit_mask = PCI_DMA_MASK_64_BIT;
|
||||
break;
|
||||
default:
|
||||
pci_priv->dma_bit_mask = PCI_DMA_MASK_32_BIT;
|
||||
break;
|
||||
@@ -5483,6 +5830,10 @@ void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv,
|
||||
}
|
||||
|
||||
switch (pci_priv->device_id) {
|
||||
case QCN7605_DEVICE_ID:
|
||||
scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
|
||||
QCN7605_PATH_PREFIX "%s", name);
|
||||
break;
|
||||
case QCA6390_DEVICE_ID:
|
||||
scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
|
||||
QCA6390_PATH_PREFIX "%s", name);
|
||||
@@ -5897,6 +6248,21 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool cnss_is_tme_supported(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
if (!pci_priv) {
|
||||
cnss_pr_dbg("pci_priv is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (pci_priv->device_id) {
|
||||
case PEACH_DEVICE_ID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -5907,6 +6273,10 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
|
||||
const struct mhi_controller_config *cnss_mhi_config =
|
||||
&cnss_mhi_config_default;
|
||||
|
||||
ret = cnss_qmi_init(plat_priv);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (pci_priv->device_id == QCA6174_DEVICE_ID)
|
||||
return 0;
|
||||
|
||||
@@ -5957,7 +6327,12 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
|
||||
mhi_ctrl->rddm_size = pci_priv->plat_priv->ramdump_info_v2.ramdump_size;
|
||||
if (!mhi_ctrl->rddm_size)
|
||||
mhi_ctrl->rddm_size = RAMDUMP_SIZE_DEFAULT;
|
||||
mhi_ctrl->sbl_size = SZ_512K;
|
||||
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
mhi_ctrl->sbl_size = SZ_256K;
|
||||
else
|
||||
mhi_ctrl->sbl_size = SZ_512K;
|
||||
|
||||
mhi_ctrl->seg_len = SZ_512K;
|
||||
mhi_ctrl->fbc_download = true;
|
||||
|
||||
@@ -5967,9 +6342,15 @@ static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
|
||||
|
||||
/* Satellite config only supported on KIWI V2 and later chipset */
|
||||
if (plat_priv->device_id <= QCA6490_DEVICE_ID ||
|
||||
(plat_priv->device_id == KIWI_DEVICE_ID &&
|
||||
plat_priv->device_version.major_version == 1))
|
||||
cnss_mhi_config = &cnss_mhi_config_no_satellite;
|
||||
(plat_priv->device_id == KIWI_DEVICE_ID &&
|
||||
plat_priv->device_version.major_version == 1)) {
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID)
|
||||
cnss_mhi_config = &cnss_mhi_config_genoa;
|
||||
else
|
||||
cnss_mhi_config = &cnss_mhi_config_no_satellite;
|
||||
}
|
||||
|
||||
mhi_ctrl->tme_supported_image = cnss_is_tme_supported(pci_priv);
|
||||
|
||||
ret = mhi_register_controller(mhi_ctrl, cnss_mhi_config);
|
||||
if (ret) {
|
||||
@@ -6150,6 +6531,57 @@ static void cnss_pci_wake_gpio_deinit(struct cnss_pci_data *pci_priv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
static int cnss_try_suspend(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* in the dual wlan card case, if call pci_register_driver after
|
||||
* finishing the first pcie device enumeration, it will cause
|
||||
* the cnss_pci_probe called in advance with the second wlan card,
|
||||
* and the sequence like this:
|
||||
* enter msm_pcie_enumerate -> pci_bus_add_devices -> cnss_pci_probe
|
||||
* -> exit msm_pcie_enumerate.
|
||||
* But the correct sequence we expected is like this:
|
||||
* enter msm_pcie_enumerate -> pci_bus_add_devices ->
|
||||
* exit msm_pcie_enumerate -> cnss_pci_probe.
|
||||
* And this unexpected sequence will make the second wlan card do
|
||||
* pcie link suspend while the pcie enumeration not finished.
|
||||
* So need to add below logical to avoid doing pcie link suspend
|
||||
* if the enumeration has not finish.
|
||||
*/
|
||||
plat_priv->enumerate_done = true;
|
||||
|
||||
/* Now enumeration is finished, try to suspend PCIe link */
|
||||
if (plat_priv->bus_priv) {
|
||||
struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
|
||||
struct pci_dev *pci_dev = pci_priv->pci_dev;
|
||||
|
||||
switch (pci_dev->device) {
|
||||
case QCA6390_DEVICE_ID:
|
||||
cnss_pci_set_wlaon_pwr_ctrl(pci_priv,
|
||||
false,
|
||||
true,
|
||||
false);
|
||||
|
||||
cnss_pci_suspend_pwroff(pci_dev);
|
||||
break;
|
||||
default:
|
||||
cnss_pr_err("Unknown PCI device found: 0x%x\n",
|
||||
pci_dev->device);
|
||||
ret = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int cnss_try_suspend(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setting to use this cnss_pm_domain ops will let PM framework override the
|
||||
* ops from dev->bus->pm which is pci_dev_pm_ops from pci-driver.c. This ops
|
||||
* has to take care everything device driver needed which is currently done
|
||||
@@ -6238,10 +6670,13 @@ static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
|
||||
static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
|
||||
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
|
||||
int rc_num = pci_dev->bus->domain_nr;
|
||||
struct cnss_plat_data *plat_priv;
|
||||
int ret = 0;
|
||||
bool suspend_pwroff = cnss_should_suspend_pwroff(pci_dev);
|
||||
|
||||
plat_priv = cnss_get_plat_priv_by_rc_num(rc_num);
|
||||
|
||||
if (suspend_pwroff) {
|
||||
ret = cnss_suspend_pci_link(pci_priv);
|
||||
if (ret)
|
||||
@@ -6259,11 +6694,17 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
|
||||
{
|
||||
int ret = 0;
|
||||
struct cnss_pci_data *pci_priv;
|
||||
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
|
||||
struct device *dev = &pci_dev->dev;
|
||||
int rc_num = pci_dev->bus->domain_nr;
|
||||
struct cnss_plat_data *plat_priv = cnss_get_plat_priv_by_rc_num(rc_num);
|
||||
|
||||
cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
|
||||
id->vendor, pci_dev->device);
|
||||
cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x rc_num %d\n",
|
||||
id->vendor, pci_dev->device, rc_num);
|
||||
if (!plat_priv) {
|
||||
cnss_pr_err("Find match plat_priv with rc number failure\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pci_priv = devm_kzalloc(dev, sizeof(*pci_priv), GFP_KERNEL);
|
||||
if (!pci_priv) {
|
||||
@@ -6332,11 +6773,16 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
|
||||
break;
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
case PEACH_DEVICE_ID:
|
||||
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
|
||||
if ((cnss_is_dual_wlan_enabled() &&
|
||||
plat_priv->enumerate_done) || !cnss_is_dual_wlan_enabled())
|
||||
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false,
|
||||
false);
|
||||
|
||||
timer_setup(&pci_priv->dev_rddm_timer,
|
||||
cnss_dev_rddm_timeout_hdlr, 0);
|
||||
timer_setup(&pci_priv->boot_debug_timer,
|
||||
@@ -6357,7 +6803,11 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
|
||||
cnss_pci_config_regs(pci_priv);
|
||||
if (EMULATION_HW)
|
||||
goto out;
|
||||
if (cnss_is_dual_wlan_enabled() && !plat_priv->enumerate_done)
|
||||
goto probe_done;
|
||||
cnss_pci_suspend_pwroff(pci_dev);
|
||||
|
||||
probe_done:
|
||||
set_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state);
|
||||
|
||||
return 0;
|
||||
@@ -6397,6 +6847,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev)
|
||||
switch (pci_dev->device) {
|
||||
case QCA6290_DEVICE_ID:
|
||||
case QCA6390_DEVICE_ID:
|
||||
case QCN7605_DEVICE_ID:
|
||||
case QCA6490_DEVICE_ID:
|
||||
case KIWI_DEVICE_ID:
|
||||
case MANGO_DEVICE_ID:
|
||||
@@ -6427,6 +6878,7 @@ static const struct pci_device_id cnss_pci_id_table[] = {
|
||||
{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ QCA6390_VENDOR_ID, QCA6390_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ QCN7605_VENDOR_ID, QCN7605_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ QCA6490_VENDOR_ID, QCA6490_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ KIWI_VENDOR_ID, KIWI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
{ MANGO_VENDOR_ID, MANGO_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
|
||||
@@ -6443,7 +6895,7 @@ static const struct dev_pm_ops cnss_pm_ops = {
|
||||
cnss_pci_runtime_idle)
|
||||
};
|
||||
|
||||
struct pci_driver cnss_pci_driver = {
|
||||
static struct pci_driver cnss_pci_driver = {
|
||||
.name = "cnss_pci",
|
||||
.id_table = cnss_pci_id_table,
|
||||
.probe = cnss_pci_probe,
|
||||
@@ -6515,17 +6967,25 @@ int cnss_pci_init(struct cnss_plat_data *plat_priv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pci_register_driver(&cnss_pci_driver);
|
||||
ret = cnss_try_suspend(plat_priv);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
|
||||
ret);
|
||||
cnss_pr_err("Failed to suspend, ret: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!plat_priv->bus_priv) {
|
||||
cnss_pr_err("Failed to probe PCI driver\n");
|
||||
ret = -ENODEV;
|
||||
goto unreg_pci;
|
||||
if (!cnss_driver_registered) {
|
||||
ret = pci_register_driver(&cnss_pci_driver);
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to register to PCI framework, err = %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
if (!plat_priv->bus_priv) {
|
||||
cnss_pr_err("Failed to probe PCI driver\n");
|
||||
ret = -ENODEV;
|
||||
goto unreg_pci;
|
||||
}
|
||||
cnss_driver_registered = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -6538,5 +6998,8 @@ out:
|
||||
|
||||
void cnss_pci_deinit(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
pci_unregister_driver(&cnss_pci_driver);
|
||||
if (cnss_driver_registered) {
|
||||
pci_unregister_driver(&cnss_pci_driver);
|
||||
cnss_driver_registered = false;
|
||||
}
|
||||
}
|
||||
|
14
cnss2/pci.h
14
cnss2/pci.h
@@ -23,7 +23,13 @@
|
||||
|
||||
#define PM_OPTIONS_DEFAULT 0
|
||||
#define PCI_LINK_DOWN 0
|
||||
|
||||
#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
|
||||
#define LINK_TRAINING_RETRY_MAX_TIMES 2
|
||||
#else
|
||||
#define LINK_TRAINING_RETRY_MAX_TIMES 3
|
||||
#endif
|
||||
|
||||
#define LINK_TRAINING_RETRY_DELAY_MS 500
|
||||
#define MSI_USERS 4
|
||||
|
||||
@@ -295,4 +301,12 @@ void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv);
|
||||
|
||||
int cnss_pci_update_time_sync_period(struct cnss_pci_data *pci_priv,
|
||||
unsigned int time_sync_period);
|
||||
int cnss_pci_set_therm_cdev_state(struct cnss_pci_data *pci_priv,
|
||||
unsigned long thermal_state,
|
||||
int tcdev_id);
|
||||
int cnss_pci_get_user_msi_assignment(struct cnss_pci_data *pci_priv,
|
||||
char *user_name,
|
||||
int *num_vectors,
|
||||
u32 *user_base_data,
|
||||
u32 *base_vector);
|
||||
#endif /* _CNSS_PCI_H */
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -74,9 +74,11 @@ static struct cnss_clk_cfg cnss_clk_list[] = {
|
||||
#define WLAN_EN_SLEEP "wlan_en_sleep"
|
||||
#define WLAN_VREGS_PROP "wlan_vregs"
|
||||
|
||||
/* unit us */
|
||||
#define BOOTSTRAP_DELAY 1000
|
||||
#define WLAN_ENABLE_DELAY 1000
|
||||
#define WLAN_ENABLE_DELAY_ROME 10000
|
||||
/* unit ms */
|
||||
#define WLAN_ENABLE_DELAY_ROME 10
|
||||
|
||||
#define TCS_CMD_DATA_ADDR_OFFSET 0x4
|
||||
#define TCS_OFFSET 0xC8
|
||||
@@ -1024,7 +1026,7 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
|
||||
|
||||
if (plat_priv->device_id == QCA6174_DEVICE_ID ||
|
||||
plat_priv->device_id == 0)
|
||||
udelay(WLAN_ENABLE_DELAY_ROME);
|
||||
mdelay(WLAN_ENABLE_DELAY_ROME);
|
||||
else
|
||||
udelay(WLAN_ENABLE_DELAY);
|
||||
|
||||
@@ -1607,6 +1609,7 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
struct device *dev = &plat_priv->plat_dev->dev;
|
||||
int ret;
|
||||
u32 cfg_arr_size = 0, *cfg_arr = NULL;
|
||||
|
||||
/* common DT Entries */
|
||||
plat_priv->pdc_init_table_len =
|
||||
@@ -1616,13 +1619,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
|
||||
plat_priv->pdc_init_table =
|
||||
kcalloc(plat_priv->pdc_init_table_len,
|
||||
sizeof(char *), GFP_KERNEL);
|
||||
ret =
|
||||
of_property_read_string_array(dev->of_node,
|
||||
"qcom,pdc_init_table",
|
||||
plat_priv->pdc_init_table,
|
||||
plat_priv->pdc_init_table_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Failed to get PDC Init Table\n");
|
||||
if (plat_priv->pdc_init_table) {
|
||||
ret = of_property_read_string_array(dev->of_node,
|
||||
"qcom,pdc_init_table",
|
||||
plat_priv->pdc_init_table,
|
||||
plat_priv->pdc_init_table_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Failed to get PDC Init Table\n");
|
||||
} else {
|
||||
cnss_pr_err("Failed to alloc PDC Init Table mem\n");
|
||||
}
|
||||
} else {
|
||||
cnss_pr_dbg("PDC Init Table not configured\n");
|
||||
}
|
||||
@@ -1634,13 +1640,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
|
||||
plat_priv->vreg_pdc_map =
|
||||
kcalloc(plat_priv->vreg_pdc_map_len,
|
||||
sizeof(char *), GFP_KERNEL);
|
||||
ret =
|
||||
of_property_read_string_array(dev->of_node,
|
||||
"qcom,vreg_pdc_map",
|
||||
plat_priv->vreg_pdc_map,
|
||||
plat_priv->vreg_pdc_map_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Failed to get VReg PDC Mapping\n");
|
||||
if (plat_priv->vreg_pdc_map) {
|
||||
ret = of_property_read_string_array(dev->of_node,
|
||||
"qcom,vreg_pdc_map",
|
||||
plat_priv->vreg_pdc_map,
|
||||
plat_priv->vreg_pdc_map_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Failed to get VReg PDC Mapping\n");
|
||||
} else {
|
||||
cnss_pr_err("Failed to alloc VReg PDC mem\n");
|
||||
}
|
||||
} else {
|
||||
cnss_pr_dbg("VReg PDC Mapping not configured\n");
|
||||
}
|
||||
@@ -1651,12 +1660,16 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
|
||||
if (plat_priv->pmu_vreg_map_len > 0) {
|
||||
plat_priv->pmu_vreg_map = kcalloc(plat_priv->pmu_vreg_map_len,
|
||||
sizeof(char *), GFP_KERNEL);
|
||||
ret =
|
||||
of_property_read_string_array(dev->of_node, "qcom,pmu_vreg_map",
|
||||
plat_priv->pmu_vreg_map,
|
||||
plat_priv->pmu_vreg_map_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Fail to get PMU VReg Mapping\n");
|
||||
if (plat_priv->pmu_vreg_map) {
|
||||
ret = of_property_read_string_array(dev->of_node,
|
||||
"qcom,pmu_vreg_map",
|
||||
plat_priv->pmu_vreg_map,
|
||||
plat_priv->pmu_vreg_map_len);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Fail to get PMU VReg Mapping\n");
|
||||
} else {
|
||||
cnss_pr_err("Failed to alloc PMU VReg mem\n");
|
||||
}
|
||||
} else {
|
||||
cnss_pr_dbg("PMU VReg Mapping not configured\n");
|
||||
}
|
||||
@@ -1676,6 +1689,25 @@ void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv)
|
||||
if (ret)
|
||||
cnss_pr_dbg("VReg for QCA6490 Int Power Amp not configured\n");
|
||||
}
|
||||
ret = of_property_count_u32_elems(plat_priv->plat_dev->dev.of_node,
|
||||
"qcom,on-chip-pmic-support");
|
||||
if (ret > 0) {
|
||||
cfg_arr_size = ret;
|
||||
cfg_arr = kcalloc(cfg_arr_size, sizeof(*cfg_arr), GFP_KERNEL);
|
||||
if (cfg_arr) {
|
||||
ret = of_property_read_u32_array(plat_priv->plat_dev->dev.of_node,
|
||||
"qcom,on-chip-pmic-support",
|
||||
cfg_arr, cfg_arr_size);
|
||||
if (!ret) {
|
||||
plat_priv->on_chip_pmic_devices_count = cfg_arr_size;
|
||||
plat_priv->on_chip_pmic_board_ids = cfg_arr;
|
||||
}
|
||||
} else {
|
||||
cnss_pr_err("Failed to alloc cfg table mem\n");
|
||||
}
|
||||
} else {
|
||||
cnss_pr_dbg("On chip PMIC device ids not configured\n");
|
||||
}
|
||||
}
|
||||
|
||||
int cnss_update_cpr_info(struct cnss_plat_data *plat_priv)
|
||||
|
145
cnss2/qmi.c
145
cnss2/qmi.c
@@ -40,6 +40,7 @@
|
||||
#endif
|
||||
#define HW_V1_NUMBER "v1"
|
||||
#define HW_V2_NUMBER "v2"
|
||||
#define CE_MSI_NAME "CE"
|
||||
|
||||
#define QMI_WLFW_TIMEOUT_MS (plat_priv->ctrl_params.qmi_timeout)
|
||||
#define QMI_WLFW_TIMEOUT_JF msecs_to_jiffies(QMI_WLFW_TIMEOUT_MS)
|
||||
@@ -597,6 +598,22 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
|
||||
if (resp->ol_cpr_cfg_valid)
|
||||
cnss_aop_ol_cpr_cfg_setup(plat_priv, &resp->ol_cpr_cfg);
|
||||
|
||||
/* Disable WLAN PDC in AOP firmware for boards which support on chip PMIC
|
||||
* so AOP will ignore SW_CTRL changes and do not update regulator votes.
|
||||
**/
|
||||
for (i = 0; i < plat_priv->on_chip_pmic_devices_count; i++) {
|
||||
if (plat_priv->board_info.board_id ==
|
||||
plat_priv->on_chip_pmic_board_ids[i]) {
|
||||
cnss_pr_dbg("Disabling WLAN PDC for board_id: %02x\n",
|
||||
plat_priv->board_info.board_id);
|
||||
ret = cnss_aop_send_msg(plat_priv,
|
||||
"{class: wlan_pdc, ss: rf, res: pdc, enable: 0}");
|
||||
if (ret < 0)
|
||||
cnss_pr_dbg("Failed to Send AOP Msg");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, otp_version: 0x%x\n",
|
||||
plat_priv->chip_info.chip_id,
|
||||
plat_priv->chip_info.chip_family,
|
||||
@@ -622,6 +639,21 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *cnss_bdf_type_to_str(enum cnss_bdf_type bdf_type)
|
||||
{
|
||||
switch (bdf_type) {
|
||||
case CNSS_BDF_BIN:
|
||||
case CNSS_BDF_ELF:
|
||||
return "BDF";
|
||||
case CNSS_BDF_REGDB:
|
||||
return "REGDB";
|
||||
case CNSS_BDF_HDS:
|
||||
return "HDS";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv,
|
||||
u32 bdf_type, char *filename,
|
||||
u32 filename_len)
|
||||
@@ -841,8 +873,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
|
||||
unsigned int remaining;
|
||||
int ret = 0;
|
||||
|
||||
cnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n",
|
||||
plat_priv->driver_state, bdf_type);
|
||||
cnss_pr_dbg("Sending QMI_WLFW_BDF_DOWNLOAD_REQ_V01 message for bdf_type: %d (%s), state: 0x%lx\n",
|
||||
bdf_type, cnss_bdf_type_to_str(bdf_type), plat_priv->driver_state);
|
||||
|
||||
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
if (!req)
|
||||
@@ -867,14 +899,16 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
|
||||
&plat_priv->plat_dev->dev);
|
||||
|
||||
if (ret) {
|
||||
cnss_pr_err("Failed to load BDF: %s, ret: %d\n", filename, ret);
|
||||
cnss_pr_err("Failed to load %s: %s, ret: %d\n",
|
||||
cnss_bdf_type_to_str(bdf_type), filename, ret);
|
||||
goto err_req_fw;
|
||||
}
|
||||
|
||||
temp = fw_entry->data;
|
||||
remaining = fw_entry->size;
|
||||
|
||||
cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
|
||||
cnss_pr_dbg("Downloading %s: %s, size: %u\n",
|
||||
cnss_bdf_type_to_str(bdf_type), filename, remaining);
|
||||
|
||||
while (remaining) {
|
||||
req->valid = 1;
|
||||
@@ -900,8 +934,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
|
||||
ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
|
||||
wlfw_bdf_download_resp_msg_v01_ei, resp);
|
||||
if (ret < 0) {
|
||||
cnss_pr_err("Failed to initialize txn for BDF download request, err: %d\n",
|
||||
ret);
|
||||
cnss_pr_err("Failed to initialize txn for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, error: %d\n",
|
||||
cnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
@@ -912,21 +946,22 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
|
||||
wlfw_bdf_download_req_msg_v01_ei, req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
cnss_pr_err("Failed to send respond BDF download request, err: %d\n",
|
||||
ret);
|
||||
cnss_pr_err("Failed to send QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, error: %d\n",
|
||||
cnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
|
||||
if (ret < 0) {
|
||||
cnss_pr_err("Failed to wait for response of BDF download request, err: %d\n",
|
||||
ret);
|
||||
cnss_pr_err("Timeout while waiting for FW response for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s, err: %d\n",
|
||||
cnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
cnss_pr_err("BDF download request failed, result: %d, err: %d\n",
|
||||
resp->resp.result, resp->resp.error);
|
||||
cnss_pr_err("FW response for QMI_WLFW_BDF_DOWNLOAD_REQ_V01 request for %s failed, result: %d, err: %d\n",
|
||||
cnss_bdf_type_to_str(bdf_type), resp->resp.result,
|
||||
resp->resp.error);
|
||||
ret = -resp->resp.result;
|
||||
goto err_send;
|
||||
}
|
||||
@@ -1533,7 +1568,7 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
|
||||
struct wlfw_wlan_cfg_req_msg_v01 *req;
|
||||
struct wlfw_wlan_cfg_resp_msg_v01 *resp;
|
||||
struct qmi_txn txn;
|
||||
u32 i;
|
||||
u32 i, ce_id, num_vectors, user_base_data, base_vector;
|
||||
int ret = 0;
|
||||
|
||||
if (!plat_priv)
|
||||
@@ -1583,16 +1618,34 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
|
||||
if (plat_priv->device_id != KIWI_DEVICE_ID &&
|
||||
plat_priv->device_id != MANGO_DEVICE_ID &&
|
||||
plat_priv->device_id != PEACH_DEVICE_ID) {
|
||||
req->shadow_reg_v2_valid = 1;
|
||||
if (config->num_shadow_reg_v2_cfg >
|
||||
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
|
||||
req->shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
|
||||
else
|
||||
req->shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
|
||||
if (plat_priv->device_id == QCN7605_DEVICE_ID &&
|
||||
config->num_shadow_reg_cfg) {
|
||||
req->shadow_reg_valid = 1;
|
||||
if (config->num_shadow_reg_cfg >
|
||||
QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
|
||||
req->shadow_reg_len =
|
||||
QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
|
||||
else
|
||||
req->shadow_reg_len =
|
||||
config->num_shadow_reg_cfg;
|
||||
memcpy(req->shadow_reg, config->shadow_reg_cfg,
|
||||
sizeof(struct wlfw_shadow_reg_cfg_s_v01) *
|
||||
req->shadow_reg_len);
|
||||
} else {
|
||||
req->shadow_reg_v2_valid = 1;
|
||||
|
||||
memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg,
|
||||
sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
|
||||
* req->shadow_reg_v2_len);
|
||||
if (config->num_shadow_reg_v2_cfg >
|
||||
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
|
||||
req->shadow_reg_v2_len =
|
||||
QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
|
||||
else
|
||||
req->shadow_reg_v2_len =
|
||||
config->num_shadow_reg_v2_cfg;
|
||||
|
||||
memcpy(req->shadow_reg_v2, config->shadow_reg_v2_cfg,
|
||||
sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) *
|
||||
req->shadow_reg_v2_len);
|
||||
}
|
||||
} else {
|
||||
req->shadow_reg_v3_valid = 1;
|
||||
if (config->num_shadow_reg_v3_cfg >
|
||||
@@ -1607,8 +1660,33 @@ int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
|
||||
plat_priv->num_shadow_regs_v3);
|
||||
|
||||
memcpy(req->shadow_reg_v3, config->shadow_reg_v3_cfg,
|
||||
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01)
|
||||
* req->shadow_reg_v3_len);
|
||||
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01) *
|
||||
req->shadow_reg_v3_len);
|
||||
}
|
||||
|
||||
if (config->rri_over_ddr_cfg_valid) {
|
||||
req->rri_over_ddr_cfg_valid = 1;
|
||||
req->rri_over_ddr_cfg.base_addr_low =
|
||||
config->rri_over_ddr_cfg.base_addr_low;
|
||||
req->rri_over_ddr_cfg.base_addr_high =
|
||||
config->rri_over_ddr_cfg.base_addr_high;
|
||||
}
|
||||
if (config->send_msi_ce) {
|
||||
ret = cnss_bus_get_msi_assignment(plat_priv,
|
||||
CE_MSI_NAME,
|
||||
&num_vectors,
|
||||
&user_base_data,
|
||||
&base_vector);
|
||||
if (!ret) {
|
||||
req->msi_cfg_valid = 1;
|
||||
req->msi_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
|
||||
for (ce_id = 0; ce_id < QMI_WLFW_MAX_NUM_CE_V01;
|
||||
ce_id++) {
|
||||
req->msi_cfg[ce_id].ce_id = ce_id;
|
||||
req->msi_cfg[ce_id].msi_vector =
|
||||
(ce_id % num_vectors) + base_vector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
|
||||
@@ -3211,9 +3289,25 @@ static struct qmi_ops qmi_wlfw_ops = {
|
||||
.del_server = wlfw_del_server,
|
||||
};
|
||||
|
||||
static int cnss_qmi_add_lookup(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
unsigned int id = WLFW_SERVICE_INS_ID_V01;
|
||||
|
||||
/* In order to support dual wlan card attach case,
|
||||
* need separate qmi service instance id for each dev
|
||||
*/
|
||||
if (cnss_is_dual_wlan_enabled() && plat_priv->qrtr_node_id != 0 &&
|
||||
plat_priv->wlfw_service_instance_id != 0)
|
||||
id = plat_priv->wlfw_service_instance_id;
|
||||
|
||||
return qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
|
||||
WLFW_SERVICE_VERS_V01, id);
|
||||
}
|
||||
|
||||
int cnss_qmi_init(struct cnss_plat_data *plat_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
cnss_get_qrtr_info(plat_priv);
|
||||
|
||||
ret = qmi_handle_init(&plat_priv->qmi_wlfw,
|
||||
QMI_WLFW_MAX_RECV_BUF_SIZE,
|
||||
@@ -3224,8 +3318,7 @@ int cnss_qmi_init(struct cnss_plat_data *plat_priv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qmi_add_lookup(&plat_priv->qmi_wlfw, WLFW_SERVICE_ID_V01,
|
||||
WLFW_SERVICE_VERS_V01, WLFW_SERVICE_INS_ID_V01);
|
||||
ret = cnss_qmi_add_lookup(plat_priv);
|
||||
if (ret < 0)
|
||||
cnss_pr_err("Failed to add WLFW QMI lookup, err: %d\n", ret);
|
||||
|
||||
|
@@ -124,6 +124,7 @@
|
||||
#define QCA6390_PCIE_SOC_PCIE_WRAP_INTR_STATUS_SOC_PCIE_REG 0x1E04058
|
||||
#define QCA6390_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG 0x01E05090
|
||||
#define PEACH_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG 0x01E01100
|
||||
#define QCA6390_PCIE_SOC_PCIE_REG_PCIE_SCRATCH_2_SOC_PCIE_REG 0x01E0405C
|
||||
#define QCA6390_PCIE_PCIE_PARF_LTSSM 0x01E081B0
|
||||
#define QCA6390_PCIE_PCIE_PARF_PM_STTS 0x01E08024
|
||||
#define QCA6390_PCIE_PCIE_PARF_PM_STTS_1 0x01E08028
|
||||
@@ -360,4 +361,6 @@
|
||||
|
||||
#define GCC_GCC_SPARE_REG_1 0x1E40310
|
||||
#define GCC_PRE_ARES_DEBUG_TIMER_VAL 0x1E40270
|
||||
|
||||
#define QCN7605_WINDOW_ENABLE_BIT 0x80000000
|
||||
#endif
|
||||
|
@@ -422,6 +422,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
|
||||
continue;
|
||||
case ICNSS_SLATE_UP:
|
||||
seq_puts(s, "ICNSS SLATE UP");
|
||||
continue;
|
||||
case ICNSS_LOW_POWER:
|
||||
seq_puts(s, "ICNSS LOW POWER");
|
||||
}
|
||||
|
||||
seq_printf(s, "UNKNOWN-%d", i);
|
||||
@@ -472,7 +475,7 @@ static int icnss_stats_show(struct seq_file *s, void *data)
|
||||
ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
|
||||
ICNSS_STATS_DUMP(s, priv, pm_relax);
|
||||
|
||||
if (priv->device_id != WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID) {
|
||||
seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
|
||||
ICNSS_STATS_DUMP(s, priv, msa_info_req);
|
||||
ICNSS_STATS_DUMP(s, priv, msa_info_resp);
|
||||
|
265
icnss2/main.c
265
icnss2/main.c
@@ -45,7 +45,7 @@
|
||||
#include <linux/soc/qcom/pdr.h>
|
||||
#include <linux/remoteproc.h>
|
||||
#include <trace/hooks/remoteproc.h>
|
||||
#include <../drivers/soc/qcom/slatecom_interface.h>
|
||||
#include <linux/soc/qcom/slatecom_interface.h>
|
||||
#include "main.h"
|
||||
#include "qmi.h"
|
||||
#include "debug.h"
|
||||
@@ -83,8 +83,13 @@ module_param(qmi_timeout, ulong, 0600);
|
||||
#define WLFW_TIMEOUT msecs_to_jiffies(3000)
|
||||
#endif
|
||||
|
||||
#define ICNSS_RECOVERY_TIMEOUT 60000
|
||||
#define ICNSS_WPSS_SSR_TIMEOUT 5000
|
||||
#define ICNSS_CAL_TIMEOUT 40000
|
||||
|
||||
static struct icnss_priv *penv;
|
||||
static struct work_struct wpss_loader;
|
||||
static struct work_struct wpss_ssr_work;
|
||||
uint64_t dynamic_feature_mask = ICNSS_DEFAULT_FEATURE_MASK;
|
||||
|
||||
#define ICNSS_EVENT_PENDING 2989
|
||||
@@ -132,14 +137,29 @@ static struct icnss_priv *icnss_get_plat_priv(void)
|
||||
return penv;
|
||||
}
|
||||
|
||||
static inline void icnss_wpss_unload(struct icnss_priv *priv)
|
||||
{
|
||||
if (priv && priv->rproc) {
|
||||
rproc_shutdown(priv->rproc);
|
||||
rproc_put(priv->rproc);
|
||||
priv->rproc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t icnss_sysfs_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct icnss_priv *priv = icnss_get_plat_priv();
|
||||
|
||||
atomic_set(&priv->is_shutdown, true);
|
||||
if (!priv)
|
||||
return count;
|
||||
|
||||
icnss_pr_dbg("Received shutdown indication");
|
||||
|
||||
atomic_set(&priv->is_shutdown, true);
|
||||
if (priv->wpss_supported && priv->device_id == ADRASTEA_DEVICE_ID)
|
||||
icnss_wpss_unload(priv);
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -449,7 +469,7 @@ static int icnss_send_smp2p(struct icnss_priv *priv,
|
||||
unsigned int value = 0;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(priv->smp2p_info[smp2p_entry].smem_state))
|
||||
if (!priv || IS_ERR(priv->smp2p_info[smp2p_entry].smem_state))
|
||||
return -EINVAL;
|
||||
|
||||
/* No Need to check FW_DOWN for ICNSS_RESET_MSG */
|
||||
@@ -502,6 +522,15 @@ static int icnss_send_smp2p(struct icnss_priv *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool icnss_is_low_power(void)
|
||||
{
|
||||
if (!penv)
|
||||
return false;
|
||||
else
|
||||
return test_bit(ICNSS_LOW_POWER, &penv->state);
|
||||
}
|
||||
EXPORT_SYMBOL(icnss_is_low_power);
|
||||
|
||||
static irqreturn_t fw_error_fatal_handler(int irq, void *ctx)
|
||||
{
|
||||
struct icnss_priv *priv = ctx;
|
||||
@@ -522,6 +551,10 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
|
||||
icnss_pr_err("Received early crash indication from FW\n");
|
||||
|
||||
if (priv) {
|
||||
if (priv->wpss_self_recovery_enabled)
|
||||
mod_timer(&priv->wpss_ssr_timer,
|
||||
jiffies + msecs_to_jiffies(ICNSS_WPSS_SSR_TIMEOUT));
|
||||
|
||||
set_bit(ICNSS_FW_DOWN, &priv->state);
|
||||
icnss_ignore_fw_timeout(true);
|
||||
|
||||
@@ -863,7 +896,8 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
if (!icnss_get_temperature(priv, &temp)) {
|
||||
icnss_pr_dbg("Temperature: %d\n", temp);
|
||||
if (temp < WLAN_EN_TEMP_THRESHOLD)
|
||||
@@ -895,6 +929,9 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6450_DEVICE_ID)
|
||||
icnss_hw_power_off(priv);
|
||||
|
||||
ret = wlfw_cap_send_sync_msg(priv);
|
||||
if (ret < 0) {
|
||||
ignore_assert = true;
|
||||
@@ -905,7 +942,8 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
ret = wlfw_device_info_send_msg(priv);
|
||||
if (ret < 0) {
|
||||
ignore_assert = true;
|
||||
@@ -945,7 +983,15 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
|
||||
goto device_info_failure;
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6450_DEVICE_ID) {
|
||||
ret = icnss_wlfw_qdss_dnld_send_sync(priv);
|
||||
if (ret < 0)
|
||||
icnss_pr_info("Failed to download qdss config file for WCN6450, ret = %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
if (!priv->fw_soc_wake_ack_irq)
|
||||
register_soc_wake_notif(&priv->pdev->dev);
|
||||
|
||||
@@ -1071,6 +1117,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
|
||||
clear_bit(ICNSS_PDR, &priv->state);
|
||||
clear_bit(ICNSS_REJUVENATE, &priv->state);
|
||||
clear_bit(ICNSS_PD_RESTART, &priv->state);
|
||||
clear_bit(ICNSS_LOW_POWER, &priv->state);
|
||||
priv->early_crash_ind = false;
|
||||
priv->is_ssr = false;
|
||||
|
||||
@@ -1124,11 +1171,13 @@ static int icnss_driver_event_fw_ready_ind(struct icnss_priv *priv, void *data)
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
del_timer(&priv->recovery_timer);
|
||||
set_bit(ICNSS_FW_READY, &priv->state);
|
||||
clear_bit(ICNSS_MODE_ON, &priv->state);
|
||||
atomic_set(&priv->soc_wake_ref_count, 0);
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID)
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID)
|
||||
icnss_free_qdss_mem(priv);
|
||||
|
||||
icnss_pr_info("WLAN FW is ready: 0x%lx\n", priv->state);
|
||||
@@ -1169,14 +1218,21 @@ static int icnss_driver_event_fw_init_done(struct icnss_priv *priv, void *data)
|
||||
|
||||
icnss_pr_info("WLAN FW Initialization done: 0x%lx\n", priv->state);
|
||||
|
||||
if (icnss_wlfw_qdss_dnld_send_sync(priv))
|
||||
icnss_pr_info("Failed to download qdss configuration file");
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
ret = icnss_wlfw_qdss_dnld_send_sync(priv);
|
||||
if (ret < 0)
|
||||
icnss_pr_info("Failed to download qdss config file for WCN6750, ret = %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (test_bit(ICNSS_COLD_BOOT_CAL, &priv->state))
|
||||
if (test_bit(ICNSS_COLD_BOOT_CAL, &priv->state)) {
|
||||
mod_timer(&priv->recovery_timer,
|
||||
jiffies + msecs_to_jiffies(ICNSS_CAL_TIMEOUT));
|
||||
ret = wlfw_wlan_mode_send_sync_msg(priv,
|
||||
(enum wlfw_driver_mode_enum_v01)ICNSS_CALIBRATION);
|
||||
else
|
||||
} else {
|
||||
icnss_driver_event_fw_ready_ind(priv, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1560,7 +1616,8 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
|
||||
if (priv->force_err_fatal)
|
||||
ICNSS_ASSERT(0);
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
icnss_send_smp2p(priv, ICNSS_RESET_MSG,
|
||||
ICNSS_SMP2P_OUT_SOC_WAKE);
|
||||
icnss_send_smp2p(priv, ICNSS_RESET_MSG,
|
||||
@@ -1759,6 +1816,19 @@ static int icnss_subsys_restart_level(struct icnss_priv *priv, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void icnss_wpss_self_recovery(struct work_struct *wpss_load_work)
|
||||
{
|
||||
int ret;
|
||||
struct icnss_priv *priv = icnss_get_plat_priv();
|
||||
|
||||
rproc_shutdown(priv->rproc);
|
||||
ret = rproc_boot(priv->rproc);
|
||||
if (ret) {
|
||||
icnss_pr_err("Failed to self recover wpss rproc, ret: %d", ret);
|
||||
rproc_put(priv->rproc);
|
||||
}
|
||||
}
|
||||
|
||||
static void icnss_driver_event_work(struct work_struct *work)
|
||||
{
|
||||
struct icnss_priv *priv =
|
||||
@@ -2063,20 +2133,25 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
|
||||
if (code != QCOM_SSR_BEFORE_SHUTDOWN)
|
||||
goto out;
|
||||
|
||||
if (priv->wpss_self_recovery_enabled)
|
||||
del_timer(&priv->wpss_ssr_timer);
|
||||
|
||||
priv->is_ssr = true;
|
||||
|
||||
icnss_pr_info("WPSS went down, state: 0x%lx, crashed: %d\n",
|
||||
priv->state, notif->crashed);
|
||||
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID)
|
||||
icnss_update_state_send_modem_shutdown(priv, data);
|
||||
|
||||
set_bit(ICNSS_FW_DOWN, &priv->state);
|
||||
icnss_ignore_fw_timeout(true);
|
||||
|
||||
if (notif->crashed)
|
||||
priv->stats.recovery.root_pd_crash++;
|
||||
else
|
||||
priv->stats.recovery.root_pd_shutdown++;
|
||||
|
||||
icnss_ignore_fw_timeout(true);
|
||||
|
||||
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
|
||||
|
||||
if (event_data == NULL)
|
||||
@@ -2094,6 +2169,10 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
|
||||
}
|
||||
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
|
||||
ICNSS_EVENT_SYNC, event_data);
|
||||
|
||||
if (notif->crashed)
|
||||
mod_timer(&priv->recovery_timer,
|
||||
jiffies + msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
|
||||
out:
|
||||
icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state);
|
||||
return NOTIFY_OK;
|
||||
@@ -2112,15 +2191,29 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
|
||||
icnss_pr_vdbg("Modem-Notify: event %s(%lu)\n",
|
||||
icnss_qcom_ssr_notify_state_to_str(code), code);
|
||||
|
||||
if (code == QCOM_SSR_AFTER_SHUTDOWN) {
|
||||
icnss_pr_info("Collecting msa0 segment dump\n");
|
||||
icnss_msa0_ramdump(priv);
|
||||
switch (code) {
|
||||
case QCOM_SSR_BEFORE_SHUTDOWN:
|
||||
if (!notif->crashed &&
|
||||
priv->low_power_support) { /* Hibernate */
|
||||
if (test_bit(ICNSS_MODE_ON, &priv->state))
|
||||
icnss_driver_event_post(
|
||||
priv, ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
|
||||
ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
|
||||
set_bit(ICNSS_LOW_POWER, &priv->state);
|
||||
}
|
||||
break;
|
||||
case QCOM_SSR_AFTER_SHUTDOWN:
|
||||
/* Collect ramdump only when there was a crash. */
|
||||
if (notif->crashed) {
|
||||
icnss_pr_info("Collecting msa0 segment dump\n");
|
||||
icnss_msa0_ramdump(priv);
|
||||
}
|
||||
|
||||
goto out;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (code != QCOM_SSR_BEFORE_SHUTDOWN)
|
||||
goto out;
|
||||
|
||||
priv->is_ssr = true;
|
||||
|
||||
if (notif->crashed) {
|
||||
@@ -2171,6 +2264,10 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
|
||||
}
|
||||
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
|
||||
ICNSS_EVENT_SYNC, event_data);
|
||||
|
||||
if (notif->crashed)
|
||||
mod_timer(&priv->recovery_timer,
|
||||
jiffies + msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
|
||||
out:
|
||||
icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state);
|
||||
return NOTIFY_OK;
|
||||
@@ -2351,6 +2448,9 @@ static void icnss_pdr_notifier_cb(int state, char *service_path, void *priv_cb)
|
||||
struct icnss_uevent_fw_down_data fw_down_data = {0};
|
||||
enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH;
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
|
||||
state, priv->state);
|
||||
|
||||
@@ -2393,6 +2493,12 @@ static void icnss_pdr_notifier_cb(int state, char *service_path, void *priv_cb)
|
||||
}
|
||||
}
|
||||
clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
|
||||
|
||||
if (event_data->crashed)
|
||||
mod_timer(&priv->recovery_timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(ICNSS_RECOVERY_TIMEOUT));
|
||||
|
||||
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
|
||||
ICNSS_EVENT_SYNC, event_data);
|
||||
break;
|
||||
@@ -2527,7 +2633,8 @@ static int icnss_register_ramdump_devices(struct icnss_priv *priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
priv->m3_dump_phyareg = icnss_create_ramdump_device(priv,
|
||||
ICNSS_M3_SEGMENT(
|
||||
ICNSS_M3_SEGMENT_PHYAREG));
|
||||
@@ -2883,7 +2990,7 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(icnss_unregister_driver);
|
||||
|
||||
static struct icnss_msi_config msi_config = {
|
||||
static struct icnss_msi_config msi_config_wcn6750 = {
|
||||
.total_vectors = 28,
|
||||
.total_users = 2,
|
||||
.users = (struct icnss_msi_user[]) {
|
||||
@@ -2892,9 +2999,20 @@ static struct icnss_msi_config msi_config = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct icnss_msi_config msi_config_wcn6450 = {
|
||||
.total_vectors = 10,
|
||||
.total_users = 1,
|
||||
.users = (struct icnss_msi_user[]) {
|
||||
{ .name = "CE", .num_vectors = 10, .base_vector = 0 },
|
||||
},
|
||||
};
|
||||
|
||||
static int icnss_get_msi_assignment(struct icnss_priv *priv)
|
||||
{
|
||||
priv->msi_config = &msi_config;
|
||||
if (priv->device_id == WCN6750_DEVICE_ID)
|
||||
priv->msi_config = &msi_config_wcn6750;
|
||||
else
|
||||
priv->msi_config = &msi_config_wcn6450;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3336,7 +3454,7 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config,
|
||||
const char *host_version)
|
||||
{
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
int temp = 0;
|
||||
int temp = 0, ret = 0;
|
||||
|
||||
if (test_bit(ICNSS_FW_DOWN, &priv->state) ||
|
||||
!test_bit(ICNSS_FW_READY, &priv->state)) {
|
||||
@@ -3363,7 +3481,15 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config,
|
||||
}
|
||||
}
|
||||
|
||||
return icnss_send_wlan_enable_to_fw(priv, config, mode, host_version);
|
||||
if (priv->device_id == WCN6450_DEVICE_ID)
|
||||
icnss_hw_power_off(priv);
|
||||
|
||||
ret = icnss_send_wlan_enable_to_fw(priv, config, mode, host_version);
|
||||
|
||||
if (priv->device_id == WCN6450_DEVICE_ID)
|
||||
icnss_hw_power_on(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(icnss_wlan_enable);
|
||||
|
||||
@@ -3799,15 +3925,6 @@ static void icnss_wpss_load(struct work_struct *wpss_load_work)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void icnss_wpss_unload(struct icnss_priv *priv)
|
||||
{
|
||||
if (priv && priv->rproc) {
|
||||
rproc_shutdown(priv->rproc);
|
||||
rproc_put(priv->rproc);
|
||||
priv->rproc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t wpss_boot_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@@ -3840,7 +3957,7 @@ static ssize_t wlan_en_delay_store(struct device *dev,
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
uint32_t wlan_en_delay = 0;
|
||||
|
||||
if (priv->device_id != WCN6750_DEVICE_ID)
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID)
|
||||
return count;
|
||||
|
||||
if (sscanf(buf, "%du", &wlan_en_delay) != 1) {
|
||||
@@ -3990,6 +4107,12 @@ static int icnss_resource_parse(struct icnss_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,is_low_power")) {
|
||||
priv->low_power_support = true;
|
||||
icnss_pr_dbg("Deep Sleep/Hibernate mode supported\n");
|
||||
}
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "qcom,rf_subtype",
|
||||
&priv->rf_subtype) == 0) {
|
||||
priv->is_rf_subtype_valid = true;
|
||||
@@ -4001,7 +4124,8 @@ static int icnss_resource_parse(struct icnss_priv *priv)
|
||||
priv->is_slate_rfa = true;
|
||||
icnss_pr_err("SLATE rfa is enabled\n");
|
||||
}
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"msi_addr");
|
||||
if (!res) {
|
||||
@@ -4038,7 +4162,7 @@ static int icnss_resource_parse(struct icnss_priv *priv)
|
||||
priv->msi_base_data, int_prop);
|
||||
|
||||
icnss_get_msi_assignment(priv);
|
||||
for (i = 0; i < msi_config.total_vectors; i++) {
|
||||
for (i = 0; i < priv->msi_config->total_vectors; i++) {
|
||||
res = platform_get_resource(priv->pdev,
|
||||
IORESOURCE_IRQ, i);
|
||||
if (!res) {
|
||||
@@ -4189,7 +4313,8 @@ static int icnss_smmu_dt_parse(struct icnss_priv *priv)
|
||||
if (!ret && !strcmp("fastmap", iommu_dma_type)) {
|
||||
icnss_pr_dbg("SMMU S1 stage enabled\n");
|
||||
priv->smmu_s1_enable = true;
|
||||
if (priv->device_id == WCN6750_DEVICE_ID)
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID)
|
||||
iommu_set_fault_handler(priv->iommu_domain,
|
||||
icnss_smmu_fault_handler,
|
||||
priv);
|
||||
@@ -4255,16 +4380,19 @@ void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID)
|
||||
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
|
||||
ADRASTEA_PATH_PREFIX "%s", name);
|
||||
else
|
||||
else if (priv->device_id == WCN6750_DEVICE_ID)
|
||||
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
|
||||
QCA6750_PATH_PREFIX "%s", name);
|
||||
|
||||
else if (priv->device_id == WCN6450_DEVICE_ID)
|
||||
scnprintf(prefix_name, ICNSS_MAX_FILE_NAME,
|
||||
WCN6450_PATH_PREFIX "%s", name);
|
||||
icnss_pr_dbg("File added with prefix: %s\n", prefix_name);
|
||||
}
|
||||
|
||||
static const struct platform_device_id icnss_platform_id_table[] = {
|
||||
{ .name = "wcn6750", .driver_data = WCN6750_DEVICE_ID, },
|
||||
{ .name = "adrastea", .driver_data = ADRASTEA_DEVICE_ID, },
|
||||
{ .name = "wcn6450", .driver_data = WCN6450_DEVICE_ID, },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -4275,6 +4403,9 @@ static const struct of_device_id icnss_dt_match[] = {
|
||||
{
|
||||
.compatible = "qcom,icnss",
|
||||
.data = (void *)&icnss_platform_id_table[1]},
|
||||
{
|
||||
.compatible = "qcom,wcn6450",
|
||||
.data = (void *)&icnss_platform_id_table[2]},
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -4305,6 +4436,10 @@ static void icnss_read_device_configs(struct icnss_priv *priv)
|
||||
"wlan-ipa-disabled")) {
|
||||
set_bit(ICNSS_IPA_DISABLED, &priv->device_config);
|
||||
}
|
||||
|
||||
if (of_property_read_bool(priv->pdev->dev.of_node,
|
||||
"qcom,wpss-self-recovery"))
|
||||
priv->wpss_self_recovery_enabled = true;
|
||||
}
|
||||
|
||||
static inline void icnss_runtime_pm_init(struct icnss_priv *priv)
|
||||
@@ -4444,7 +4579,8 @@ static int icnss_probe(struct platform_device *pdev)
|
||||
if (priv->is_slate_rfa)
|
||||
init_completion(&priv->slate_boot_complete);
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
priv->soc_wake_wq = alloc_workqueue("icnss_soc_wake_event",
|
||||
WQ_UNBOUND|WQ_HIGHPRI, 1);
|
||||
if (!priv->soc_wake_wq) {
|
||||
@@ -4478,6 +4614,15 @@ static int icnss_probe(struct platform_device *pdev)
|
||||
INIT_WORK(&wpss_loader, icnss_wpss_load);
|
||||
}
|
||||
|
||||
timer_setup(&priv->recovery_timer,
|
||||
icnss_recovery_timeout_hdlr, 0);
|
||||
|
||||
if (priv->wpss_self_recovery_enabled) {
|
||||
INIT_WORK(&wpss_ssr_work, icnss_wpss_self_recovery);
|
||||
timer_setup(&priv->wpss_ssr_timer,
|
||||
icnss_wpss_ssr_timeout_hdlr, 0);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&priv->icnss_tcdev_list);
|
||||
|
||||
icnss_pr_info("Platform driver probed successfully\n");
|
||||
@@ -4528,6 +4673,11 @@ static int icnss_remove(struct platform_device *pdev)
|
||||
|
||||
icnss_pr_info("Removing driver: state: 0x%lx\n", priv->state);
|
||||
|
||||
del_timer(&priv->recovery_timer);
|
||||
|
||||
if (priv->wpss_self_recovery_enabled)
|
||||
del_timer(&priv->wpss_ssr_timer);
|
||||
|
||||
device_init_wakeup(&priv->pdev->dev, false);
|
||||
|
||||
icnss_debugfs_destroy(priv);
|
||||
@@ -4552,7 +4702,8 @@ static int icnss_remove(struct platform_device *pdev)
|
||||
icnss_pdr_unregister_notifier(priv);
|
||||
}
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
icnss_genl_exit();
|
||||
icnss_runtime_pm_deinit(priv);
|
||||
if (!IS_ERR_OR_NULL(priv->mbox_chan))
|
||||
@@ -4586,6 +4737,23 @@ static int icnss_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void icnss_recovery_timeout_hdlr(struct timer_list *t)
|
||||
{
|
||||
struct icnss_priv *priv = from_timer(priv, t, recovery_timer);
|
||||
|
||||
icnss_pr_err("Timeout waiting for FW Ready 0x%lx\n", priv->state);
|
||||
ICNSS_ASSERT(0);
|
||||
}
|
||||
|
||||
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t)
|
||||
{
|
||||
struct icnss_priv *priv = from_timer(priv, t, wpss_ssr_timer);
|
||||
|
||||
icnss_pr_err("Timeout waiting for WPSS SSR notification 0x%lx\n",
|
||||
priv->state);
|
||||
schedule_work(&wpss_ssr_work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int icnss_pm_suspend(struct device *dev)
|
||||
{
|
||||
@@ -4608,7 +4776,8 @@ static int icnss_pm_suspend(struct device *dev)
|
||||
ret = priv->ops->pm_suspend(dev);
|
||||
|
||||
if (ret == 0) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
|
||||
!test_bit(ICNSS_MODE_ON, &priv->state))
|
||||
return 0;
|
||||
@@ -4717,7 +4886,7 @@ static int icnss_pm_runtime_suspend(struct device *dev)
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (priv->device_id != WCN6750_DEVICE_ID) {
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID) {
|
||||
icnss_pr_err("Ignore runtime suspend:\n");
|
||||
goto out;
|
||||
}
|
||||
@@ -4751,8 +4920,8 @@ static int icnss_pm_runtime_resume(struct device *dev)
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (priv->device_id != WCN6750_DEVICE_ID) {
|
||||
icnss_pr_err("Ignore runtime resume:\n");
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID) {
|
||||
icnss_pr_err("Ignore runtime resume\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -4778,8 +4947,8 @@ static int icnss_pm_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct icnss_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (priv->device_id != WCN6750_DEVICE_ID) {
|
||||
icnss_pr_err("Ignore runtime idle:\n");
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID) {
|
||||
icnss_pr_err("Ignore runtime idle\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@@ -19,14 +19,17 @@
|
||||
#endif
|
||||
#include "wlan_firmware_service_v01.h"
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#define WCN6750_DEVICE_ID 0x6750
|
||||
#define WCN6450_DEVICE_ID 0x6450
|
||||
#define ADRASTEA_DEVICE_ID 0xabcd
|
||||
#define THERMAL_NAME_LENGTH 20
|
||||
#define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF
|
||||
#define ICNSS_SMEM_SEQ_NO_POS 16
|
||||
#define QCA6750_PATH_PREFIX "qca6750/"
|
||||
#define ADRASTEA_PATH_PREFIX "adrastea/"
|
||||
#define WCN6450_PATH_PREFIX "wcn6450/"
|
||||
#define ICNSS_MAX_FILE_NAME 35
|
||||
#define ICNSS_PCI_EP_WAKE_OFFSET 4
|
||||
#define ICNSS_DISABLE_M3_SSR 0
|
||||
@@ -127,6 +130,7 @@ enum icnss_driver_state {
|
||||
ICNSS_QMI_DMS_CONNECTED,
|
||||
ICNSS_SLATE_SSR_REGISTERED,
|
||||
ICNSS_SLATE_UP,
|
||||
ICNSS_LOW_POWER,
|
||||
};
|
||||
|
||||
struct ce_irq_list {
|
||||
@@ -497,10 +501,14 @@ struct icnss_priv {
|
||||
struct workqueue_struct *soc_update_wq;
|
||||
unsigned long device_config;
|
||||
bool wpss_supported;
|
||||
u8 low_power_support;
|
||||
bool is_rf_subtype_valid;
|
||||
u32 rf_subtype;
|
||||
u8 is_slate_rfa;
|
||||
struct completion slate_boot_complete;
|
||||
struct timer_list recovery_timer;
|
||||
struct timer_list wpss_ssr_timer;
|
||||
bool wpss_self_recovery_enabled;
|
||||
};
|
||||
|
||||
struct icnss_reg_info {
|
||||
@@ -528,5 +536,7 @@ int icnss_update_cpr_info(struct icnss_priv *priv);
|
||||
void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
|
||||
char *name);
|
||||
int icnss_aop_mbox_init(struct icnss_priv *priv);
|
||||
void icnss_recovery_timeout_hdlr(struct timer_list *t);
|
||||
void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
|
||||
#endif
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -38,6 +39,13 @@ static struct icnss_battery_level icnss_battery_level[] = {
|
||||
{0, 2850000},
|
||||
};
|
||||
|
||||
static struct icnss_vreg_cfg icnss_wcn6450_vreg_list[] = {
|
||||
{"vdd-cx-mx", 824000, 952000, 0, 0, 0, false, true},
|
||||
{"vdd-1.8-xo", 1872000, 1872000, 0, 0, 0, false, true},
|
||||
{"vdd-1.3-rfa", 1256000, 1352000, 0, 0, 0, false, true},
|
||||
{"vdd-aon", 1256000, 1352000, 0, 0, 0, false, true},
|
||||
};
|
||||
|
||||
static struct icnss_clk_cfg icnss_clk_list[] = {
|
||||
{"rf_clk", 0, 0},
|
||||
};
|
||||
@@ -48,6 +56,7 @@ static struct icnss_clk_cfg icnss_adrestea_clk_list[] = {
|
||||
|
||||
#define ICNSS_VREG_LIST_SIZE ARRAY_SIZE(icnss_wcn6750_vreg_list)
|
||||
#define ICNSS_VREG_ADRESTEA_LIST_SIZE ARRAY_SIZE(icnss_adrestea_vreg_list)
|
||||
#define ICNSS_VREG_EVROS_LIST_SIZE ARRAY_SIZE(icnss_wcn6450_vreg_list)
|
||||
#define ICNSS_CLK_LIST_SIZE ARRAY_SIZE(icnss_clk_list)
|
||||
#define ICNSS_CLK_ADRESTEA_LIST_SIZE ARRAY_SIZE(icnss_adrestea_clk_list)
|
||||
|
||||
@@ -311,6 +320,10 @@ static struct icnss_vreg_cfg *get_vreg_list(u32 *vreg_list_size,
|
||||
*vreg_list_size = ICNSS_VREG_ADRESTEA_LIST_SIZE;
|
||||
return icnss_adrestea_vreg_list;
|
||||
|
||||
case WCN6450_DEVICE_ID:
|
||||
*vreg_list_size = ICNSS_VREG_EVROS_LIST_SIZE;
|
||||
return icnss_wcn6450_vreg_list;
|
||||
|
||||
default:
|
||||
icnss_pr_err("Unsupported device_id 0x%x\n", device_id);
|
||||
*vreg_list_size = 0;
|
||||
@@ -524,7 +537,8 @@ int icnss_get_clk(struct icnss_priv *priv)
|
||||
if (priv->device_id == ADRASTEA_DEVICE_ID) {
|
||||
clk_cfg = icnss_adrestea_clk_list;
|
||||
clk_list_size = ICNSS_CLK_ADRESTEA_LIST_SIZE;
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
clk_cfg = icnss_clk_list;
|
||||
clk_list_size = ICNSS_CLK_LIST_SIZE;
|
||||
}
|
||||
|
22
icnss2/qmi.c
22
icnss2/qmi.c
@@ -1,7 +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.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "icnss2_qmi: " fmt
|
||||
@@ -55,6 +55,9 @@
|
||||
#define DMS_MAC_NOT_PROVISIONED 16
|
||||
#define BDWLAN_SIZE 6
|
||||
#define UMC_CHIP_ID 0x4320
|
||||
#define MAX_SHADOW_REG_RESERVED 2
|
||||
#define MAX_NUM_SHADOW_REG_V3 (QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 - \
|
||||
MAX_SHADOW_REG_RESERVED)
|
||||
|
||||
#ifdef CONFIG_ICNSS2_DEBUG
|
||||
bool ignore_fw_timeout;
|
||||
@@ -546,7 +549,8 @@ int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv)
|
||||
req->rejuvenate_enable_valid = 1;
|
||||
req->rejuvenate_enable = 1;
|
||||
}
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID) {
|
||||
} else if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID) {
|
||||
req->fw_init_done_enable_valid = 1;
|
||||
req->fw_init_done_enable = 1;
|
||||
req->cal_done_enable_valid = 1;
|
||||
@@ -2969,7 +2973,8 @@ int icnss_register_fw_service(struct icnss_priv *priv)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (priv->device_id == WCN6750_DEVICE_ID)
|
||||
if (priv->device_id == WCN6750_DEVICE_ID ||
|
||||
priv->device_id == WCN6450_DEVICE_ID)
|
||||
ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01,
|
||||
WLFW_SERVICE_VERS_V01,
|
||||
WLFW_SERVICE_WCN_INS_ID_V01);
|
||||
@@ -3060,6 +3065,17 @@ int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv,
|
||||
|
||||
memcpy(req.shadow_reg, config->shadow_reg_cfg,
|
||||
sizeof(struct wlfw_msi_cfg_s_v01) * req.shadow_reg_len);
|
||||
} else if (priv->device_id == WCN6450_DEVICE_ID) {
|
||||
req.shadow_reg_v3_valid = 1;
|
||||
if (config->num_shadow_reg_v3_cfg >
|
||||
MAX_NUM_SHADOW_REG_V3)
|
||||
req.shadow_reg_v3_len = MAX_NUM_SHADOW_REG_V3;
|
||||
else
|
||||
req.shadow_reg_v3_len = config->num_shadow_reg_v3_cfg;
|
||||
|
||||
memcpy(req.shadow_reg_v3, config->shadow_reg_v3_cfg,
|
||||
sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01)
|
||||
* req.shadow_reg_v3_len);
|
||||
}
|
||||
|
||||
ret = wlfw_wlan_cfg_send_sync_msg(priv, &req);
|
||||
|
17
inc/cnss2.h
17
inc/cnss2.h
@@ -15,12 +15,6 @@
|
||||
#define CNSS_MAX_DEV_MEM_NUM 4
|
||||
#define CNSS_CHIP_VER_ANY 0
|
||||
|
||||
/*
|
||||
* Temporary change for compilation, will be removed
|
||||
* after WLAN host driver switched to use new APIs
|
||||
*/
|
||||
#define CNSS_API_WITH_DEV
|
||||
|
||||
#define CNSS_SSR_DRIVER_DUMP_MAX_REGIONS 32
|
||||
|
||||
enum cnss_bus_width_type {
|
||||
@@ -179,6 +173,9 @@ struct cnss_wlan_driver {
|
||||
int (*collect_driver_dump)(struct pci_dev *pdev,
|
||||
struct cnss_ssr_driver_dump_entry *input_array,
|
||||
size_t *num_entries_loaded);
|
||||
int (*set_therm_cdev_state)(struct pci_dev *pci_dev,
|
||||
unsigned long thermal_state,
|
||||
int tcdev_id);
|
||||
};
|
||||
|
||||
struct cnss_ce_tgt_pipe_cfg {
|
||||
@@ -227,6 +224,7 @@ struct cnss_wlan_enable_cfg {
|
||||
struct cnss_rri_over_ddr_cfg rri_over_ddr_cfg;
|
||||
u32 num_shadow_reg_v3_cfg;
|
||||
struct cnss_shadow_reg_v3_cfg *shadow_reg_v3_cfg;
|
||||
bool send_msi_ce;
|
||||
};
|
||||
|
||||
enum cnss_driver_mode {
|
||||
@@ -353,4 +351,11 @@ extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb,
|
||||
extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid);
|
||||
extern bool cnss_get_fw_cap(struct device *dev, enum cnss_fw_caps fw_cap);
|
||||
extern int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg);
|
||||
extern int cnss_thermal_cdev_register(struct device *dev,
|
||||
unsigned long max_state,
|
||||
int tcdev_id);
|
||||
extern void cnss_thermal_cdev_unregister(struct device *dev, int tcdev_id);
|
||||
extern int cnss_get_curr_therm_cdev_state(struct device *dev,
|
||||
unsigned long *thermal_state,
|
||||
int tcdev_id);
|
||||
#endif /* _NET_CNSS2_H */
|
||||
|
12
inc/icnss2.h
12
inc/icnss2.h
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef _ICNSS_WLAN_H_
|
||||
#define _ICNSS_WLAN_H_
|
||||
@@ -13,10 +14,6 @@
|
||||
#define ICNSS_MAX_TIMESTAMP_LEN 32
|
||||
#define ICNSS_WLFW_MAX_BUILD_ID_LEN 128
|
||||
|
||||
#ifndef ICNSS_API_WITH_DEV
|
||||
#define ICNSS_API_WITH_DEV
|
||||
#endif
|
||||
|
||||
#define DEVICE_NAME_MAX 10
|
||||
enum icnss_uevent {
|
||||
ICNSS_UEVENT_FW_CRASHED,
|
||||
@@ -98,6 +95,10 @@ struct icnss_shadow_reg_v2_cfg {
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
struct icnss_shadow_reg_v3_cfg {
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
struct icnss_rri_over_ddr_cfg {
|
||||
u32 base_addr_low;
|
||||
u32 base_addr_high;
|
||||
@@ -112,6 +113,8 @@ struct icnss_wlan_enable_cfg {
|
||||
struct icnss_shadow_reg_cfg *shadow_reg_cfg;
|
||||
u32 num_shadow_reg_v2_cfg;
|
||||
struct icnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg;
|
||||
u32 num_shadow_reg_v3_cfg;
|
||||
struct icnss_shadow_reg_v3_cfg *shadow_reg_v3_cfg;
|
||||
bool rri_over_ddr_cfg_valid;
|
||||
struct icnss_rri_over_ddr_cfg rri_over_ddr_cfg;
|
||||
};
|
||||
@@ -180,6 +183,7 @@ extern unsigned int icnss_socinfo_get_serial_number(struct device *dev);
|
||||
extern bool icnss_is_qmi_disable(struct device *dev);
|
||||
extern bool icnss_is_fw_ready(void);
|
||||
extern bool icnss_is_fw_down(void);
|
||||
extern bool icnss_is_low_power(void);
|
||||
extern bool icnss_is_rejuvenate(void);
|
||||
extern int icnss_trigger_recovery(struct device *dev);
|
||||
extern void icnss_block_shutdown(bool status);
|
||||
|
Yeni konuda referans
Bir kullanıcı engelle