Jelajahi Sumber

Merge b15f3ce9fe8aadda108b6b4a78cfee952629bc3e on remote branch

Change-Id: I203aca24a4a9deb0bf6e2ff2ec7b52b5a0c4d2eb
Linux Build Service Account 2 tahun lalu
induk
melakukan
e5e10e3e69
18 mengubah file dengan 509 tambahan dan 50 penghapusan
  1. 4 0
      Kbuild
  2. 2 0
      Makefile
  3. 1 0
      cnss2/Makefile
  4. 1 0
      cnss2/bus.h
  5. 1 1
      cnss2/debug.c
  6. 121 13
      cnss2/main.c
  7. 5 5
      cnss2/main.h
  8. 19 8
      cnss2/pci.c
  9. 1 0
      cnss2/pci.h
  10. 44 8
      cnss2/power.c
  11. 24 1
      cnss2/qmi.c
  12. 120 2
      cnss_utils/wlan_firmware_service_v01.c
  13. 44 5
      cnss_utils/wlan_firmware_service_v01.h
  14. 33 1
      icnss2/main.c
  15. 5 2
      icnss2/main.h
  16. 72 4
      icnss2/qmi.c
  17. 8 0
      icnss2/qmi.h
  18. 4 0
      inc/cnss2.h

+ 4 - 0
Kbuild

@@ -36,6 +36,10 @@ ifeq ($(CONFIG_CNSS2_CONDITIONAL_POWEROFF),y)
 KBUILD_CPPFLAGS += -DCONFIG_CNSS2_CONDITIONAL_POWEROFF
 endif
 
+ifeq ($(CONFIG_AUTO_PROJECT),y)
+KBUILD_CPPFLAGS += -DCONFIG_PULLDOWN_WLANEN
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 2 - 0
Makefile

@@ -9,6 +9,7 @@ WLAN_PLATFORM_ROOT = $(shell pwd)
 # so enable all flags (including debug flag CONFIG_CNSS2_DEBUG) by
 # default.
 KBUILD_OPTIONS := WLAN_PLATFORM_ROOT=$(WLAN_PLATFORM_ROOT)
+ifeq ($(USE_EXTERNAL_CONFIGS),)
 KBUILD_OPTIONS += CONFIG_CNSS_OUT_OF_TREE=y
 KBUILD_OPTIONS += CONFIG_CNSS2=m
 KBUILD_OPTIONS += CONFIG_ICNSS2=m
@@ -22,6 +23,7 @@ KBUILD_OPTIONS += CONFIG_CNSS_GENL=m
 KBUILD_OPTIONS += CONFIG_WCNSS_MEM_PRE_ALLOC=m
 KBUILD_OPTIONS += CONFIG_CNSS_UTILS=m
 endif
+endif
 
 all:
 	$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)

+ 1 - 0
cnss2/Makefile

@@ -10,6 +10,7 @@ endif
 ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/smcinvoke/
 ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/linux/
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/include/linux/
 endif
 
 obj-$(CONFIG_CNSS2) += cnss2.o

+ 1 - 0
cnss2/bus.h

@@ -20,6 +20,7 @@
 #define QCA6390_DEVICE_ID		0x1101
 #define QCA6490_VENDOR_ID		0x17CB
 #define QCA6490_DEVICE_ID		0x1103
+#define QCN7605_DEVICE_ID               0x1102
 #define KIWI_VENDOR_ID			0x17CB
 #define KIWI_DEVICE_ID			0x1107
 #define MANGO_VENDOR_ID			0x17CB

+ 1 - 1
cnss2/debug.c

@@ -223,7 +223,7 @@ static ssize_t cnss_dev_boot_debug_write(struct file *fp,
 	cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
 
 	if (sysfs_streq(cmd, "on")) {
-		ret = cnss_power_on_device(plat_priv);
+		ret = cnss_power_on_device(plat_priv, false);
 	} else if (sysfs_streq(cmd, "off")) {
 		cnss_power_off_device(plat_priv);
 	} else if (sysfs_streq(cmd, "enumerate")) {

+ 121 - 13
cnss2/main.c

@@ -219,6 +219,36 @@ int cnss_get_mem_segment_info(enum cnss_remote_mem_type type,
 }
 EXPORT_SYMBOL(cnss_get_mem_segment_info);
 
+static int cnss_get_audio_iommu_domain(struct cnss_plat_data *plat_priv)
+{
+	struct device_node *audio_ion_node;
+	struct platform_device *audio_ion_pdev;
+
+	audio_ion_node = of_find_compatible_node(NULL, NULL,
+						 "qcom,msm-audio-ion");
+	if (!audio_ion_node) {
+		cnss_pr_err("Unable to get Audio ion node");
+		return -EINVAL;
+	}
+
+	audio_ion_pdev = of_find_device_by_node(audio_ion_node);
+	of_node_put(audio_ion_node);
+	if (!audio_ion_pdev) {
+		cnss_pr_err("Unable to get Audio ion platform device");
+		return -EINVAL;
+	}
+
+	plat_priv->audio_iommu_domain =
+				iommu_get_domain_for_dev(&audio_ion_pdev->dev);
+	put_device(&audio_ion_pdev->dev);
+	if (!plat_priv->audio_iommu_domain) {
+		cnss_pr_err("Unable to get Audio ion iommu domain");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 int cnss_set_feature_list(struct cnss_plat_data *plat_priv,
 			  enum cnss_feature_v01 feature)
 {
@@ -325,26 +355,28 @@ EXPORT_SYMBOL(cnss_get_platform_cap);
 bool cnss_get_fw_cap(struct device *dev, enum cnss_fw_caps fw_cap)
 {
 	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
-	bool ret = false;
+	bool is_supported = false;
 
 	if (!plat_priv)
-		return ret;
+		return is_supported;
 
 	if (!plat_priv->fw_caps)
-		return ret;
+		return is_supported;
 
 	switch (fw_cap) {
 	case CNSS_FW_CAP_DIRECT_LINK_SUPPORT:
-		ret = !!(plat_priv->fw_caps &
-			 QMI_WLFW_DIRECT_LINK_SUPPORT_V01);
+		is_supported = !!(plat_priv->fw_caps &
+				  QMI_WLFW_DIRECT_LINK_SUPPORT_V01);
+		if (is_supported && cnss_get_audio_iommu_domain(plat_priv))
+			is_supported = false;
 		break;
 	default:
 		cnss_pr_err("Invalid FW Capability: 0x%x\n", fw_cap);
 	}
 
 	cnss_pr_dbg("FW Capability 0x%x is %s\n", fw_cap,
-		    ret ? "supported" : "not supported");
-	return ret;
+		    is_supported ? "supported" : "not supported");
+	return is_supported;
 }
 EXPORT_SYMBOL(cnss_get_fw_cap);
 
@@ -375,9 +407,15 @@ int cnss_wlan_enable(struct device *dev,
 		     enum cnss_driver_mode mode,
 		     const char *host_version)
 {
-	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	int ret = 0;
+	struct cnss_plat_data *plat_priv;
+
+	if (!dev) {
+		cnss_pr_err("Invalid dev pointer\n");
+		return -EINVAL;
+	}
 
+	plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	if (!plat_priv)
 		return -ENODEV;
 
@@ -411,9 +449,15 @@ EXPORT_SYMBOL(cnss_wlan_enable);
 
 int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
 {
-	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	int ret = 0;
+	struct cnss_plat_data *plat_priv;
 
+	if (!dev) {
+		cnss_pr_err("Invalid dev pointer\n");
+		return -EINVAL;
+	}
+
+	plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	if (!plat_priv)
 		return -ENODEV;
 
@@ -430,6 +474,52 @@ int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
 }
 EXPORT_SYMBOL(cnss_wlan_disable);
 
+int cnss_audio_smmu_map(struct device *dev, phys_addr_t paddr,
+			dma_addr_t iova, size_t size)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	uint32_t page_offset;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!plat_priv->audio_iommu_domain)
+		return -EINVAL;
+
+	page_offset = iova & (PAGE_SIZE - 1);
+	if (page_offset + size > PAGE_SIZE)
+		size += PAGE_SIZE;
+
+	iova -= page_offset;
+	paddr -= page_offset;
+
+	return iommu_map(plat_priv->audio_iommu_domain, iova, paddr,
+			 roundup(size, PAGE_SIZE), IOMMU_READ | IOMMU_WRITE);
+}
+EXPORT_SYMBOL(cnss_audio_smmu_map);
+
+void cnss_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	uint32_t page_offset;
+
+	if (!plat_priv)
+		return;
+
+	if (!plat_priv->audio_iommu_domain)
+		return;
+
+	page_offset = iova & (PAGE_SIZE - 1);
+	if (page_offset + size > PAGE_SIZE)
+		size += PAGE_SIZE;
+
+	iova -= page_offset;
+
+	iommu_unmap(plat_priv->audio_iommu_domain, iova,
+		    roundup(size, PAGE_SIZE));
+}
+EXPORT_SYMBOL(cnss_audio_smmu_unmap);
+
 int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
 		      u32 data_len, u8 *output)
 {
@@ -490,8 +580,14 @@ EXPORT_SYMBOL(cnss_athdiag_write);
 
 int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
 {
-	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_plat_data *plat_priv;
+
+	if (!dev) {
+		cnss_pr_err("Invalid dev pointer\n");
+		return -EINVAL;
+	}
 
+	plat_priv = cnss_bus_dev_to_plat_priv(dev);
 	if (!plat_priv)
 		return -ENODEV;
 
@@ -1155,7 +1251,7 @@ static int cnss_get_resources(struct cnss_plat_data *plat_priv)
 	int ret = 0;
 
 	ret = cnss_get_vreg_type(plat_priv, CNSS_VREG_PRIM);
-	if (ret) {
+	if (ret < 0) {
 		cnss_pr_err("Failed to get vreg, err = %d\n", ret);
 		goto out;
 	}
@@ -2042,6 +2138,18 @@ mark_cal_fail:
 		 */
 		plat_priv->cal_done = CNSS_CAL_FAILURE;
 		set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state);
+
+		if (plat_priv->device_id == QCA6174_DEVICE_ID ||
+		    plat_priv->device_id == QCN7605_DEVICE_ID) {
+			if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state))
+				goto out;
+
+			cnss_pr_info("Schedule WLAN driver load\n");
+
+			if (cancel_delayed_work_sync(&plat_priv->wlan_reg_driver_work))
+				schedule_delayed_work(&plat_priv->wlan_reg_driver_work,
+						      0);
+		}
 	}
 
 out:
@@ -4076,7 +4184,7 @@ static int cnss_wlan_device_init(struct cnss_plat_data *plat_priv)
 		return 0;
 
 retry:
-	ret = cnss_power_on_device(plat_priv);
+	ret = cnss_power_on_device(plat_priv, true);
 	if (ret)
 		goto end;
 
@@ -4108,7 +4216,6 @@ int cnss_wlan_hw_enable(void)
 
 	if (test_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state))
 		goto register_driver;
-
 	ret = cnss_wlan_device_init(plat_priv);
 	if (ret) {
 		if (!test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state))
@@ -4301,6 +4408,7 @@ static int cnss_remove(struct platform_device *plat_dev)
 {
 	struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
 
+	plat_priv->audio_iommu_domain = NULL;
 	cnss_genl_exit();
 	cnss_unregister_ims_service(plat_priv);
 	cnss_unregister_coex_service(plat_priv);

+ 5 - 5
cnss2/main.h

@@ -39,12 +39,11 @@
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/subsystem_restart.h>
 #endif
-
+#include <linux/iommu.h>
 #include "qmi.h"
 
 #define MAX_NO_OF_MAC_ADDR		4
 #define QMI_WLFW_MAX_TIMESTAMP_LEN	32
-#define QMI_WLFW_MAX_NUM_MEM_SEG	32
 #define QMI_WLFW_MAX_BUILD_ID_LEN	128
 #define CNSS_RDDM_TIMEOUT_MS		20000
 #define RECOVERY_TIMEOUT		60000
@@ -498,7 +497,7 @@ struct cnss_plat_data {
 	char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN + 1];
 	u32 otp_version;
 	u32 fw_mem_seg_len;
-	struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG];
+	struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 	struct cnss_fw_mem m3_mem;
 	struct cnss_fw_mem *cal_mem;
 	u64 cal_time;
@@ -506,7 +505,7 @@ struct cnss_plat_data {
 	u32 cal_file_size;
 	struct completion daemon_connected;
 	u32 qdss_mem_seg_len;
-	struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG];
+	struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 	u32 *qdss_reg;
 	struct cnss_pin_connect_result pin_result;
 	struct dentry *root_dentry;
@@ -549,6 +548,7 @@ struct cnss_plat_data {
 	bool fw_pcie_gen_switch;
 	u64 fw_caps;
 	u8 pcie_gen_speed;
+	struct iommu_domain *audio_iommu_domain;
 	struct cnss_dms_data dms;
 	int power_up_error;
 	u32 hw_trc_override;
@@ -614,7 +614,7 @@ int cnss_vreg_unvote_type(struct cnss_plat_data *plat_priv,
 			  enum cnss_vreg_type type);
 int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
 int cnss_get_wlan_sw_ctrl(struct cnss_plat_data *plat_priv);
-int cnss_power_on_device(struct cnss_plat_data *plat_priv);
+int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset);
 void cnss_power_off_device(struct cnss_plat_data *plat_priv);
 bool cnss_is_device_powered_on(struct cnss_plat_data *plat_priv);
 int cnss_enable_dev_sol_irq(struct cnss_plat_data *plat_priv);

+ 19 - 8
cnss2/pci.c

@@ -1248,16 +1248,16 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
 		}
 	}
 
+	ret = cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+	if (ret)
+		goto out;
+
 	ret = pci_enable_device(pci_priv->pci_dev);
 	if (ret) {
 		cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
 		goto out;
 	}
 
-	ret = cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
-	if (ret)
-		goto out;
-
 	pci_set_master(pci_priv->pci_dev);
 
 	if (pci_priv->pci_link_down_ind)
@@ -2351,6 +2351,7 @@ int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
 		}
 		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
 		set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+		cnss_pci_free_blob_mem(pci_priv);
 		complete_all(&plat_priv->power_up_complete);
 	} else if (test_bit(CNSS_DRIVER_IDLE_RESTART,
 			    &plat_priv->driver_state)) {
@@ -2593,7 +2594,7 @@ static int cnss_qca6174_powerup(struct cnss_pci_data *pci_priv)
 	int ret = 0;
 	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
 
-	ret = cnss_power_on_device(plat_priv);
+	ret = cnss_power_on_device(plat_priv, false);
 	if (ret) {
 		cnss_pr_err("Failed to power on device, err = %d\n", ret);
 		goto out;
@@ -2703,7 +2704,7 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
 
 	cnss_get_driver_mode_update_fw_name(plat_priv);
 retry:
-	ret = cnss_power_on_device(plat_priv);
+	ret = cnss_power_on_device(plat_priv, false);
 	if (ret) {
 		cnss_pr_err("Failed to power on device, err = %d\n", ret);
 		goto out;
@@ -3096,7 +3097,6 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
 	}
 
 	pci_priv = plat_priv->bus_priv;
-
 	if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
 		while (id_table && id_table->device) {
 			if (plat_priv->device_id == id_table->device) {
@@ -4353,6 +4353,17 @@ static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv)
 	m3_mem->size = 0;
 }
 
+#ifdef CONFIG_FREE_M3_BLOB_MEM
+void cnss_pci_free_blob_mem(struct cnss_pci_data *pci_priv)
+{
+	cnss_pci_free_m3_mem(pci_priv);
+}
+#else
+void cnss_pci_free_blob_mem(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+
 void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv)
 {
 	struct cnss_plat_data *plat_priv;
@@ -6194,7 +6205,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
 	}
 
 	ret = cnss_dev_specific_power_on(plat_priv);
-	if (ret)
+	if (ret < 0)
 		goto reset_ctx;
 
 	cnss_pci_of_reserved_mem_device_init(pci_priv);

+ 1 - 0
cnss2/pci.h

@@ -232,6 +232,7 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv);
 void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_load_m3(struct cnss_pci_data *pci_priv);
+void cnss_pci_free_blob_mem(struct cnss_pci_data *pci_priv);
 int cnss_pci_handle_dev_sol_irq(struct cnss_pci_data *pci_priv);
 int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv);
 void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic);

+ 44 - 8
cnss2/power.c

@@ -76,6 +76,7 @@ static struct cnss_clk_cfg cnss_clk_list[] = {
 
 #define BOOTSTRAP_DELAY			1000
 #define WLAN_ENABLE_DELAY		1000
+#define WLAN_ENABLE_DELAY_ROME		10000
 
 #define TCS_CMD_DATA_ADDR_OFFSET	0x4
 #define TCS_OFFSET			0xC8
@@ -90,6 +91,7 @@ static struct cnss_clk_cfg cnss_clk_list[] = {
 #define CNSS_PMIC_AUTO_HEADROOM 16
 #define CNSS_IR_DROP_WAKE 30
 #define CNSS_IR_DROP_SLEEP 10
+#define VREG_NOTFOUND 1
 
 /**
  * enum cnss_aop_vreg_param: Voltage regulator TCS param
@@ -326,8 +328,10 @@ static struct cnss_vreg_cfg *get_vreg_list(u32 *vreg_list_size,
  * For multi-exchg dt node, get the required vregs' names from property
  * 'wlan_vregs', which is string array;
  *
- * if the property is present but no value is set, then no additional wlan
- * verg is required.
+ * If the property is not present or present but no value is set, then no
+ * additional wlan verg is required, function return VREG_NOTFOUND.
+ * If property is present with valid value, function return 0.
+ * Other cases a negative value is returned.
  *
  * For non-multi-exchg dt, go through all vregs in the static array
  * 'cnss_vreg_list'.
@@ -355,14 +359,19 @@ static int cnss_get_vreg(struct cnss_plat_data *plat_priv,
 		id_n = of_property_count_strings(dt_node,
 						 WLAN_VREGS_PROP);
 		if (id_n <= 0) {
-			if (id_n == -ENODATA) {
+			if (id_n == -ENODATA || id_n == -EINVAL) {
 				cnss_pr_dbg("No additional vregs for: %s:%lx\n",
 					    dt_node->name,
 					    plat_priv->device_id);
-				return 0;
+				/* By returning a positive value, give the caller a
+				 * chance to know no additional regulator is needed
+				 * by this device, and shall not treat this case as
+				 * an error.
+				 */
+				return VREG_NOTFOUND;
 			}
 
-			cnss_pr_err("property %s is invalid or missed: %s:%lx\n",
+			cnss_pr_err("property %s is invalid: %s:%lx\n",
 				    WLAN_VREGS_PROP, dt_node->name,
 				    plat_priv->device_id);
 			return -EINVAL;
@@ -1012,12 +1021,19 @@ static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
 					    ret);
 				goto out;
 			}
-			udelay(WLAN_ENABLE_DELAY);
+
+			if (plat_priv->device_id == QCA6174_DEVICE_ID ||
+			    plat_priv->device_id == 0)
+				udelay(WLAN_ENABLE_DELAY_ROME);
+			else
+				udelay(WLAN_ENABLE_DELAY);
+
 			cnss_set_xo_clk_gpio_state(plat_priv, false);
 		} else {
 			cnss_set_xo_clk_gpio_state(plat_priv, false);
 			goto out;
 		}
+
 	} else {
 		if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
 			cnss_wlan_hw_disable_check(plat_priv);
@@ -1104,7 +1120,7 @@ int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num)
 	return gpio_get_value(gpio_num);
 }
 
-int cnss_power_on_device(struct cnss_plat_data *plat_priv)
+int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset)
 {
 	int ret = 0;
 
@@ -1131,6 +1147,26 @@ int cnss_power_on_device(struct cnss_plat_data *plat_priv)
 		goto vreg_off;
 	}
 
+#ifdef CONFIG_PULLDOWN_WLANEN
+	if (reset) {
+		/* The default state of wlan_en maybe not low,
+		 * according to datasheet, we should put wlan_en
+		 * to low first, and trigger high.
+		 * And the default delay for qca6390 is at least 4ms,
+		 * for qcn7605/qca6174, it is 10us. For safe, set 5ms delay
+		 * here.
+		 */
+		ret = cnss_select_pinctrl_state(plat_priv, false);
+		if (ret) {
+			cnss_pr_err("Failed to select pinctrl state, err = %d\n",
+				    ret);
+			goto clk_off;
+		}
+
+		usleep_range(4000, 5000);
+	}
+#endif
+
 	ret = cnss_select_pinctrl_enable(plat_priv);
 	if (ret) {
 		cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret);
@@ -1788,5 +1824,5 @@ int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv)
 		return ret;
 
 	plat_priv->powered_on = false;
-	return cnss_power_on_device(plat_priv);
+	return cnss_power_on_device(plat_priv, false);
 }

+ 24 - 1
cnss2/qmi.c

@@ -395,6 +395,12 @@ int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
 		return -ENOMEM;
 	}
 
+	if (plat_priv->fw_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+		cnss_pr_err("Invalid seg len %u\n", plat_priv->fw_mem_seg_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
 	req->mem_seg_len = plat_priv->fw_mem_seg_len;
 	for (i = 0; i < req->mem_seg_len; i++) {
 		if (!fw_mem[i].pa || !fw_mem[i].size) {
@@ -1172,7 +1178,8 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n
 		     resp->total_size == total_size) &&
 		   (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) &&
 		   (resp->data_valid == 1 &&
-		    resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) {
+		    resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) &&
+		   resp->data_len <= remaining) {
 			memcpy(p_qdss_trace_data_temp,
 			       resp->data, resp->data_len);
 		} else {
@@ -2111,6 +2118,12 @@ int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv)
 		return -ENOMEM;
 	}
 
+	if (plat_priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+		cnss_pr_err("Invalid seg len %u\n", plat_priv->qdss_mem_seg_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
 	req->mem_seg_len = plat_priv->qdss_mem_seg_len;
 	for (i = 0; i < req->mem_seg_len; i++) {
 		cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
@@ -2479,6 +2492,11 @@ static void cnss_wlfw_request_mem_ind_cb(struct qmi_handle *qmi_wlfw,
 		return;
 	}
 
+	if (ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+		cnss_pr_err("Invalid seg len %u\n", ind_msg->mem_seg_len);
+		return;
+	}
+
 	plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len;
 	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
 		cnss_pr_dbg("FW requests for memory, size: 0x%x, type: %u\n",
@@ -2693,6 +2711,11 @@ static void cnss_wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi_wlfw,
 		return;
 	}
 
+	if (ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+		cnss_pr_err("Invalid seg len %u\n", ind_msg->mem_seg_len);
+		return;
+	}
+
 	plat_priv->qdss_mem_seg_len = ind_msg->mem_seg_len;
 	for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) {
 		cnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n",

+ 120 - 2
cnss_utils/wlan_firmware_service_v01.c

@@ -1,6 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2015-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 "wlan_firmware_service_v01.h"
 #include <linux/module.h>
@@ -726,6 +726,44 @@ static struct qmi_elem_info wlfw_shadow_reg_v3_cfg_s_v01_ei[] = {
 	},
 };
 
+static struct qmi_elem_info wlfw_share_mem_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_share_mem_type_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_share_mem_info_s_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_share_mem_info_s_v01,
+					   start),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_share_mem_info_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
 struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[] = {
 	{
 		.data_type      = QMI_OPT_FLAG,
@@ -4023,6 +4061,37 @@ struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[] = {
 					   resp),
 		.ei_array      = qmi_response_type_v01_ei,
 	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_respond_mem_resp_msg_v01,
+					   share_mem_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_respond_mem_resp_msg_v01,
+					   share_mem_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHARE_MEM_V01,
+		.elem_size      = sizeof(struct wlfw_share_mem_info_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_respond_mem_resp_msg_v01,
+					   share_mem),
+		.ei_array      = wlfw_share_mem_info_s_v01_ei,
+	},
 	{
 		.data_type      = QMI_EOTI,
 		.array_type       = NO_ARRAY,
@@ -6183,6 +6252,55 @@ struct qmi_elem_info wlfw_phy_cap_resp_msg_v01_ei[] = {
 };
 EXPORT_SYMBOL(wlfw_phy_cap_resp_msg_v01_ei);
 
+struct qmi_elem_info wlfw_wlan_hw_init_cfg_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wlan_hw_init_cfg_req_msg_v01,
+					   rf_subtype_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_wlan_rf_subtype_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wlan_hw_init_cfg_req_msg_v01,
+					   rf_subtype),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wlan_hw_init_cfg_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wlan_hw_init_cfg_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_wlan_hw_init_cfg_resp_msg_v01,
+					   resp),
+		.ei_array      = qmi_response_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wlan_hw_init_cfg_resp_msg_v01_ei);
+
 /**
  * wlfw_is_valid_dt_node_found - Check if valid device tree node present
  *

+ 44 - 5
cnss_utils/wlan_firmware_service_v01.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2015-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. */
 
 #ifndef WLAN_FIRMWARE_SERVICE_V01_H
 #define WLAN_FIRMWARE_SERVICE_V01_H
@@ -60,6 +60,7 @@
 #define QMI_WLFW_ANTENNA_GRANT_REQ_V01 0x0048
 #define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
 #define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
+#define QMI_WLFW_WLAN_HW_INIT_CFG_REQ_V01 0x0058
 #define QMI_WLFW_RESPOND_GET_INFO_IND_V01 0x004B
 #define QMI_WLFW_QDSS_TRACE_DATA_REQ_V01 0x0042
 #define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
@@ -100,6 +101,7 @@
 #define QMI_WLFW_WFC_CALL_STATUS_REQ_V01 0x0049
 #define QMI_WLFW_DEVICE_INFO_RESP_V01 0x004C
 #define QMI_WLFW_MSA_READY_RESP_V01 0x002E
+#define QMI_WLFW_WLAN_HW_INIT_CFG_RESP_V01 0x0058
 #define QMI_WLFW_INI_FILE_DOWNLOAD_REQ_V01 0x0056
 #define QMI_WLFW_QDSS_TRACE_FREE_IND_V01 0x0046
 #define QMI_WLFW_QDSS_MEM_READY_IND_V01 0x0052
@@ -110,6 +112,7 @@
 #define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
 #define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
 #define QMI_WLFW_MAX_DEV_MEM_NUM_V01 4
+#define QMI_WLFW_MAX_NUM_SHARE_MEM_V01 8
 #define QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01 2
 #define QMI_WLFW_MAX_NUM_SVC_V01 24
 #define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
@@ -182,6 +185,16 @@ enum wlfw_mem_type_enum_v01 {
 	WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
 };
 
+enum wlfw_share_mem_type_enum_v01 {
+	WLFW_SHARE_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_SHARE_MEM_CRASHDBG_V01 = 0,
+	QMI_WLFW_SHARE_MEM_TXSAR_V01 = 1,
+	QMI_WLFW_SHARE_MEM_AFC_V01 = 2,
+	QMI_WLFW_SHARE_MEM_REMOTE_COPY_V01 = 3,
+	QMI_WLFW_SHARE_MEM_MAX_V01 = 8,
+	WLFW_SHARE_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
 enum wlfw_qdss_trace_mode_enum_v01 {
 	WLFW_QDSS_TRACE_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
 	QMI_WLFW_QDSS_TRACE_OFF_V01 = 0,
@@ -293,6 +306,13 @@ enum wlfw_ini_file_type_v01 {
 	WLFW_INI_FILE_TYPE_MAX_VAL_V01 = INT_MAX,
 };
 
+enum wlfw_wlan_rf_subtype_v01 {
+	WLFW_WLAN_RF_SUBTYPE_MIN_VAL_V01 = INT_MIN,
+	WLFW_WLAN_RF_SLATE_V01 = 0,
+	WLFW_WLAN_RF_APACHE_V01 = 1,
+	WLFW_WLAN_RF_SUBTYPE_MAX_VAL_V01 = INT_MAX,
+};
+
 #define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
 #define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
 #define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
@@ -432,6 +452,12 @@ struct wlfw_shadow_reg_v3_cfg_s_v01 {
 	u32 addr;
 };
 
+struct wlfw_share_mem_info_s_v01 {
+	enum wlfw_share_mem_type_enum_v01 type;
+	u64 start;
+	u64 size;
+};
+
 struct wlfw_ind_register_req_msg_v01 {
 	u8 fw_ready_enable_valid;
 	u8 fw_ready_enable;
@@ -520,7 +546,6 @@ struct wlfw_wlan_mode_req_msg_v01 {
 	u8 wlan_en_delay_valid;
 	u32 wlan_en_delay;
 };
-
 #define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 22
 extern struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[];
 
@@ -616,7 +641,6 @@ struct wlfw_cap_resp_msg_v01 {
 	u8 rxgainlut_support_valid;
 	u8 rxgainlut_support;
 };
-
 #define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 1146
 extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[];
 
@@ -924,8 +948,11 @@ extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[];
 
 struct wlfw_respond_mem_resp_msg_v01 {
 	struct qmi_response_type_v01 resp;
+	u8 share_mem_valid;
+	u32 share_mem_len;
+	struct wlfw_share_mem_info_s_v01 share_mem[QMI_WLFW_MAX_NUM_SHARE_MEM_V01];
 };
-#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
+#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 171
 extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[];
 
 struct wlfw_fw_mem_ready_ind_msg_v01 {
@@ -1024,7 +1051,6 @@ struct wlfw_qdss_trace_mem_info_req_msg_v01 {
 	u8 end_valid;
 	u8 end;
 };
-
 #define WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN 892
 extern struct qmi_elem_info wlfw_qdss_trace_mem_info_req_msg_v01_ei[];
 
@@ -1365,4 +1391,17 @@ struct wlfw_phy_cap_resp_msg_v01 {
 #define WLFW_PHY_CAP_RESP_MSG_V01_MAX_MSG_LEN 18
 extern struct qmi_elem_info wlfw_phy_cap_resp_msg_v01_ei[];
 
+struct wlfw_wlan_hw_init_cfg_req_msg_v01 {
+	u8 rf_subtype_valid;
+	enum wlfw_wlan_rf_subtype_v01 rf_subtype;
+};
+#define WLFW_WLAN_HW_INIT_CFG_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_hw_init_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_hw_init_cfg_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_WLAN_HW_INIT_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_hw_init_cfg_resp_msg_v01_ei[];
+
 #endif

+ 33 - 1
icnss2/main.c

@@ -126,7 +126,7 @@ static void icnss_set_plat_priv(struct icnss_priv *priv)
 	penv = priv;
 }
 
-static struct icnss_priv *icnss_get_plat_priv()
+static struct icnss_priv *icnss_get_plat_priv(void)
 {
 	return penv;
 }
@@ -787,12 +787,25 @@ void icnss_set_wlan_en_delay(struct icnss_priv *priv)
 	}
 }
 
+static enum wlfw_wlan_rf_subtype_v01 icnss_rf_subtype_value_to_type(u32 val)
+{
+	switch (val) {
+	case WLAN_RF_SLATE:
+		return WLFW_WLAN_RF_SLATE_V01;
+	case WLAN_RF_APACHE:
+		return WLFW_WLAN_RF_APACHE_V01;
+	default:
+		return WLFW_WLAN_RF_SUBTYPE_MAX_VAL_V01;
+	}
+}
+
 static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
 						 void *data)
 {
 	int ret = 0;
 	int temp = 0;
 	bool ignore_assert = false;
+	enum wlfw_wlan_rf_subtype_v01 rf_subtype;
 
 	if (!priv)
 		return -ENODEV;
@@ -824,6 +837,19 @@ static int icnss_driver_event_server_arrive(struct icnss_priv *priv,
 		goto fail;
 	}
 
+	if (priv->is_rf_subtype_valid) {
+		rf_subtype = icnss_rf_subtype_value_to_type(priv->rf_subtype);
+		if (rf_subtype != WLFW_WLAN_RF_SUBTYPE_MAX_VAL_V01) {
+			ret = wlfw_wlan_hw_init_cfg_msg(priv, rf_subtype);
+			if (ret < 0)
+				icnss_pr_dbg("Sending rf_subtype failed ret %d\n",
+					     ret);
+		} else {
+			icnss_pr_dbg("Invalid rf subtype %d in DT\n",
+				     priv->rf_subtype);
+		}
+	}
+
 	if (priv->device_id == WCN6750_DEVICE_ID) {
 		if (!icnss_get_temperature(priv, &temp)) {
 			icnss_pr_dbg("Temperature: %d\n", temp);
@@ -3873,6 +3899,12 @@ static int icnss_resource_parse(struct icnss_priv *priv)
 				priv->ce_irqs[i] = res->start;
 			}
 		}
+
+		if (of_property_read_u32(pdev->dev.of_node, "qcom,rf_subtype",
+					 &priv->rf_subtype) == 0) {
+			priv->is_rf_subtype_valid = true;
+			icnss_pr_dbg("RF subtype 0x%x\n", priv->rf_subtype);
+		}
 	} else if (priv->device_id == WCN6750_DEVICE_ID) {
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						   "msi_addr");

+ 5 - 2
icnss2/main.h

@@ -21,7 +21,6 @@
 
 #define WCN6750_DEVICE_ID 0x6750
 #define ADRASTEA_DEVICE_ID 0xabcd
-#define QMI_WLFW_MAX_NUM_MEM_SEG 32
 #define THERMAL_NAME_LENGTH 20
 #define ICNSS_SMEM_VALUE_MASK 0xFFFFFFFF
 #define ICNSS_SMEM_SEQ_NO_POS 16
@@ -31,6 +30,8 @@
 #define ICNSS_PCI_EP_WAKE_OFFSET 4
 #define ICNSS_DISABLE_M3_SSR 0
 #define ICNSS_ENABLE_M3_SSR 1
+#define WLAN_RF_SLATE 0
+#define WLAN_RF_APACHE 1
 
 extern uint64_t dynamic_feature_mask;
 
@@ -455,7 +456,7 @@ struct icnss_priv {
 	struct rproc *rproc;
 	atomic_t is_shutdown;
 	u32 qdss_mem_seg_len;
-	struct icnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG];
+	struct icnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
 	void *get_info_cb_ctx;
 	int (*get_info_cb)(void *ctx, void *event, int event_len);
 	atomic_t soc_wake_ref_count;
@@ -491,6 +492,8 @@ struct icnss_priv {
 	struct workqueue_struct *soc_update_wq;
 	unsigned long device_config;
 	bool wpss_supported;
+	bool is_rf_subtype_valid;
+	u32 rf_subtype;
 };
 
 struct icnss_reg_info {

+ 72 - 4
icnss2/qmi.c

@@ -917,7 +917,7 @@ int icnss_wlfw_wlan_mac_req_send_sync(struct icnss_priv *priv,
 	}
 
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
-		icnss_pr_err("WLAN mac req failed, result: %d, err: %d\n",
+		icnss_pr_err("WLAN mac req failed, result: %d\n",
 			     resp.resp.result);
 		ret = -resp.resp.result;
 	}
@@ -1271,7 +1271,8 @@ int icnss_wlfw_qdss_data_send_sync(struct icnss_priv *priv, char *file_name,
 		     resp->total_size == total_size) &&
 		    (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) &&
 		    (resp->data_valid == 1 &&
-		     resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) {
+		     resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) &&
+		    resp->data_len <= remaining) {
 			memcpy(p_qdss_trace_data_temp,
 			       resp->data, resp->data_len);
 		} else {
@@ -2165,7 +2166,7 @@ int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv)
 
 	req->mem_seg_len = priv->qdss_mem_seg_len;
 
-	if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) {
+	if (priv->qdss_mem_seg_len >  QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
 		icnss_pr_err("Invalid seg len %u\n",
 			     priv->qdss_mem_seg_len);
 		ret = -EINVAL;
@@ -2564,7 +2565,7 @@ static void wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi,
 
 	priv->qdss_mem_seg_len = ind_msg->mem_seg_len;
 
-	if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG) {
+	if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
 		icnss_pr_err("Invalid seg len %u\n",
 			     priv->qdss_mem_seg_len);
 		return;
@@ -3456,3 +3457,70 @@ out:
 	kfree(req);
 	return ret;
 }
+
+int wlfw_wlan_hw_init_cfg_msg(struct icnss_priv *penv,
+			      enum wlfw_wlan_rf_subtype_v01 type)
+{
+	int ret;
+	struct wlfw_wlan_hw_init_cfg_req_msg_v01 *req;
+	struct wlfw_wlan_hw_init_cfg_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+
+	if (!penv)
+		return -ENODEV;
+
+	icnss_pr_dbg("Sending hw init cfg, rf_subtype: 0x%x\n", type);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->rf_subtype_valid = 1;
+	req->rf_subtype = type;
+
+	ret = qmi_txn_init(&penv->qmi, &txn,
+			   wlfw_wlan_hw_init_cfg_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		icnss_pr_err("Fail to init txn for hw init cfg, resp %d\n",
+			     ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&penv->qmi, NULL, &txn,
+			       QMI_WLFW_WLAN_HW_INIT_CFG_REQ_V01,
+			       WLFW_WLAN_HW_INIT_CFG_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_wlan_hw_init_cfg_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		icnss_pr_err("Fail to send hw init cfg %d\n", ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, penv->ctrl_params.qmi_timeout);
+	if (ret < 0) {
+		icnss_pr_err("HW init cfg timed out with ret %d\n",
+			     ret);
+		goto out;
+
+	} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		icnss_pr_err("HW init cfg request rejected,result:%d error:%d\n",
+			     resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(resp);
+	kfree(req);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}

+ 8 - 0
icnss2/qmi.h

@@ -203,6 +203,12 @@ int icnss_send_vbatt_update(struct icnss_priv *priv, uint64_t voltage_uv)
 {
 	return 0;
 }
+
+int wlfw_wlan_hw_init_cfg_msg(struct icnss_priv *penv,
+			      enum wlfw_wlan_rf_subtype_v01 type)
+{
+	return 0;
+}
 #else
 int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv);
 int icnss_connect_to_fw_server(struct icnss_priv *priv, void *data);
@@ -258,6 +264,8 @@ void icnss_dms_deinit(struct icnss_priv *priv);
 int wlfw_subsys_restart_level_msg(struct icnss_priv *penv, uint8_t restart_level);
 int wlfw_cal_report_req(struct icnss_priv *priv);
 int icnss_send_vbatt_update(struct icnss_priv *priv, uint64_t voltage_uv);
+int wlfw_wlan_hw_init_cfg_msg(struct icnss_priv *penv,
+			      enum wlfw_wlan_rf_subtype_v01 type);
 #endif
 
 #endif /* __ICNSS_QMI_H__*/

+ 4 - 0
inc/cnss2.h

@@ -305,6 +305,10 @@ extern int cnss_get_mem_seg_count(enum cnss_remote_mem_type type, u32 *seg);
 extern int cnss_get_mem_segment_info(enum cnss_remote_mem_type type,
 				     struct cnss_mem_segment segment[],
 				     u32 segment_count);
+extern int cnss_audio_smmu_map(struct device *dev, phys_addr_t paddr,
+			       dma_addr_t iova, size_t size);
+extern void cnss_audio_smmu_unmap(struct device *dev, dma_addr_t iova,
+				 size_t size);
 extern int cnss_get_pci_slot(struct device *dev);
 extern int cnss_pci_get_reg_dump(struct device *dev, uint8_t *buffer,
 				 uint32_t len);