Explorar el Código

Add 'qcom/opensource/wlan/platform/' from commit '54afb87accfa6775cef4e9adcd4e6f08c64a5fb1'

git-subtree-dir: qcom/opensource/wlan/platform
git-subtree-mainline: c74a556fc198c06018efa29a1d8bd1951278e5ec
git-subtree-split: 54afb87accfa6775cef4e9adcd4e6f08c64a5fb1
Change-Id:
repo: https://git.codelinaro.org/clo/la/platform/vendor/qcom-opensource/wlan/platform
tag: LA.VENDOR.14.3.0.r1-17300-lanai.QSSI15.0
David Wronek hace 5 meses
padre
commit
925e49bf4f
Se han modificado 100 ficheros con 38741 adiciones y 0 borrados
  1. 135 0
      qcom/opensource/wlan/platform/Android.mk
  2. 34 0
      qcom/opensource/wlan/platform/BUILD.bazel
  3. 103 0
      qcom/opensource/wlan/platform/Kbuild
  4. 48 0
      qcom/opensource/wlan/platform/Makefile
  5. 181 0
      qcom/opensource/wlan/platform/cnss2/Kconfig
  6. 28 0
      qcom/opensource/wlan/platform/cnss2/Makefile
  7. 10 0
      qcom/opensource/wlan/platform/cnss2/anorak_consolidate_defconfig
  8. 9 0
      qcom/opensource/wlan/platform/cnss2/anorak_gki_defconfig
  9. 868 0
      qcom/opensource/wlan/platform/cnss2/bus.c
  10. 86 0
      qcom/opensource/wlan/platform/cnss2/bus.h
  11. 100 0
      qcom/opensource/wlan/platform/cnss2/coexistence_service_v01.c
  12. 52 0
      qcom/opensource/wlan/platform/cnss2/coexistence_service_v01.h
  13. 1222 0
      qcom/opensource/wlan/platform/cnss2/debug.c
  14. 108 0
      qcom/opensource/wlan/platform/cnss2/debug.h
  15. 217 0
      qcom/opensource/wlan/platform/cnss2/genl.c
  16. 17 0
      qcom/opensource/wlan/platform/cnss2/genl.h
  17. 5800 0
      qcom/opensource/wlan/platform/cnss2/main.c
  18. 772 0
      qcom/opensource/wlan/platform/cnss2/main.h
  19. 12 0
      qcom/opensource/wlan/platform/cnss2/niobe_consolidate_defconfig
  20. 11 0
      qcom/opensource/wlan/platform/cnss2/niobe_gki_defconfig
  21. 7913 0
      qcom/opensource/wlan/platform/cnss2/pci.c
  22. 350 0
      qcom/opensource/wlan/platform/cnss2/pci.h
  23. 253 0
      qcom/opensource/wlan/platform/cnss2/pci_platform.h
  24. 829 0
      qcom/opensource/wlan/platform/cnss2/pci_qcom.c
  25. 12 0
      qcom/opensource/wlan/platform/cnss2/pineapple_consolidate_defconfig
  26. 11 0
      qcom/opensource/wlan/platform/cnss2/pineapple_gki_defconfig
  27. 2065 0
      qcom/opensource/wlan/platform/cnss2/power.c
  28. 4158 0
      qcom/opensource/wlan/platform/cnss2/qmi.c
  29. 356 0
      qcom/opensource/wlan/platform/cnss2/qmi.h
  30. 380 0
      qcom/opensource/wlan/platform/cnss2/reg.h
  31. 12 0
      qcom/opensource/wlan/platform/cnss2/sun_consolidate_defconfig
  32. 11 0
      qcom/opensource/wlan/platform/cnss2/sun_gki_defconfig
  33. 14 0
      qcom/opensource/wlan/platform/cnss_genl/Kconfig
  34. 9 0
      qcom/opensource/wlan/platform/cnss_genl/Makefile
  35. 2 0
      qcom/opensource/wlan/platform/cnss_genl/anorak_consolidate_defconfig
  36. 2 0
      qcom/opensource/wlan/platform/cnss_genl/anorak_gki_defconfig
  37. 2 0
      qcom/opensource/wlan/platform/cnss_genl/blair_consolidate_defconfig
  38. 2 0
      qcom/opensource/wlan/platform/cnss_genl/blair_gki_defconfig
  39. 255 0
      qcom/opensource/wlan/platform/cnss_genl/cnss_nl.c
  40. 2 0
      qcom/opensource/wlan/platform/cnss_genl/monaco_consolidate_defconfig
  41. 2 0
      qcom/opensource/wlan/platform/cnss_genl/monaco_gki_defconfig
  42. 2 0
      qcom/opensource/wlan/platform/cnss_genl/niobe_consolidate_defconfig
  43. 2 0
      qcom/opensource/wlan/platform/cnss_genl/niobe_gki_defconfig
  44. 2 0
      qcom/opensource/wlan/platform/cnss_genl/pineapple_consolidate_defconfig
  45. 2 0
      qcom/opensource/wlan/platform/cnss_genl/pineapple_gki_defconfig
  46. 2 0
      qcom/opensource/wlan/platform/cnss_genl/pitti_consolidate_defconfig
  47. 2 0
      qcom/opensource/wlan/platform/cnss_genl/pitti_gki_defconfig
  48. 2 0
      qcom/opensource/wlan/platform/cnss_genl/sun_consolidate_defconfig
  49. 2 0
      qcom/opensource/wlan/platform/cnss_genl/sun_gki_defconfig
  50. 2 0
      qcom/opensource/wlan/platform/cnss_genl/volcano_consolidate_defconfig
  51. 2 0
      qcom/opensource/wlan/platform/cnss_genl/volcano_gki_defconfig
  52. 14 0
      qcom/opensource/wlan/platform/cnss_prealloc/Kconfig
  53. 10 0
      qcom/opensource/wlan/platform/cnss_prealloc/Makefile
  54. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/anorak_consolidate_defconfig
  55. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/anorak_gki_defconfig
  56. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/blair_consolidate_defconfig
  57. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/blair_gki_defconfig
  58. 406 0
      qcom/opensource/wlan/platform/cnss_prealloc/cnss_prealloc.c
  59. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/monaco_consolidate_defconfig
  60. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/monaco_gki_defconfig
  61. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/niobe_consolidate_defconfig
  62. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/niobe_gki_defconfig
  63. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/pineapple_consolidate_defconfig
  64. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/pineapple_gki_defconfig
  65. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/pitti_consolidate_defconfig
  66. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/pitti_gki_defconfig
  67. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/sun_consolidate_defconfig
  68. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/sun_gki_defconfig
  69. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/volcano_consolidate_defconfig
  70. 2 0
      qcom/opensource/wlan/platform/cnss_prealloc/volcano_gki_defconfig
  71. 30 0
      qcom/opensource/wlan/platform/cnss_utils/Kconfig
  72. 15 0
      qcom/opensource/wlan/platform/cnss_utils/Makefile
  73. 4 0
      qcom/opensource/wlan/platform/cnss_utils/anorak_consolidate_defconfig
  74. 4 0
      qcom/opensource/wlan/platform/cnss_utils/anorak_gki_defconfig
  75. 3 0
      qcom/opensource/wlan/platform/cnss_utils/blair_consolidate_defconfig
  76. 3 0
      qcom/opensource/wlan/platform/cnss_utils/blair_gki_defconfig
  77. 25 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_common.h
  78. 988 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_qmi.c
  79. 90 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_qmi.h
  80. 402 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_service_v01.c
  81. 127 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_service_v01.h
  82. 590 0
      qcom/opensource/wlan/platform/cnss_utils/cnss_utils.c
  83. 75 0
      qcom/opensource/wlan/platform/cnss_utils/device_management_service_v01.c
  84. 38 0
      qcom/opensource/wlan/platform/cnss_utils/device_management_service_v01.h
  85. 457 0
      qcom/opensource/wlan/platform/cnss_utils/ip_multimedia_subsystem_private_service_v01.c
  86. 136 0
      qcom/opensource/wlan/platform/cnss_utils/ip_multimedia_subsystem_private_service_v01.h
  87. 3 0
      qcom/opensource/wlan/platform/cnss_utils/monaco_consolidate_defconfig
  88. 3 0
      qcom/opensource/wlan/platform/cnss_utils/monaco_gki_defconfig
  89. 4 0
      qcom/opensource/wlan/platform/cnss_utils/niobe_consolidate_defconfig
  90. 4 0
      qcom/opensource/wlan/platform/cnss_utils/niobe_gki_defconfig
  91. 4 0
      qcom/opensource/wlan/platform/cnss_utils/pineapple_consolidate_defconfig
  92. 4 0
      qcom/opensource/wlan/platform/cnss_utils/pineapple_gki_defconfig
  93. 3 0
      qcom/opensource/wlan/platform/cnss_utils/pitti_consolidate_defconfig
  94. 3 0
      qcom/opensource/wlan/platform/cnss_utils/pitti_gki_defconfig
  95. 4 0
      qcom/opensource/wlan/platform/cnss_utils/sun_consolidate_defconfig
  96. 4 0
      qcom/opensource/wlan/platform/cnss_utils/sun_gki_defconfig
  97. 3 0
      qcom/opensource/wlan/platform/cnss_utils/volcano_consolidate_defconfig
  98. 3 0
      qcom/opensource/wlan/platform/cnss_utils/volcano_gki_defconfig
  99. 7140 0
      qcom/opensource/wlan/platform/cnss_utils/wlan_firmware_service_v01.c
  100. 1637 0
      qcom/opensource/wlan/platform/cnss_utils/wlan_firmware_service_v01.h

+ 135 - 0
qcom/opensource/wlan/platform/Android.mk

@@ -0,0 +1,135 @@
+# Android Makefile for WLAN platform modules
+
+ENABLE_WLAN_PLATFORM_DLKM := false
+ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true)
+  ifeq ($(TARGET_KERNEL_DLKM_WLAN_OVERRIDE), true)
+    ENABLE_WLAN_PLATFORM_DLKM := true
+  endif
+else
+  ENABLE_WLAN_PLATFORM_DLKM := true
+endif
+
+ifeq ($(ENABLE_WLAN_PLATFORM_DLKM), true)
+
+# LOCAL_PATH is a relative path to root build directory.
+LOCAL_PATH := $(call my-dir)
+LOCAL_MODULE_DDK_BUILD := true
+LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true
+LOCAL_MODULE_KO_DIRS := cnss2/cnss2.ko
+LOCAL_MODULE_KO_DIRS += cnss_utils/cnss_plat_ipc_qmi_svc.ko
+LOCAL_MODULE_KO_DIRS += cnss_utils/wlan_firmware_service.ko
+LOCAL_MODULE_KO_DIRS += cnss_genl/cnss_nl.ko
+LOCAL_MODULE_KO_DIRS += cnss_prealloc/cnss_prealloc.ko
+LOCAL_MODULE_KO_DIRS += cnss_utils/cnss_utils.ko
+LOCAL_MODULE_KO_DIRS += icnss2/icnss2.ko
+
+BOARD_COMMON_DIR ?= device/qcom/common
+DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm
+
+# WLAN_PLATFORM_ROOT needs to be a absolute since it will be used
+# for header files. $(TOP) cannot be used here since it will be
+# resolved as "." which won't work for Kbuild.
+KBUILD_OPTIONS := WLAN_PLATFORM_ROOT=$(abspath $(LOCAL_PATH))
+
+# WLAN_PLATFORM_KBUILD_OPTIONS should be defined from upper level
+# Product or Board related Makefiles like wlan.mk.
+KBUILD_OPTIONS += $(foreach wlan_platform_kbuild_option, \
+		   $(WLAN_PLATFORM_KBUILD_OPTIONS), \
+		   $(wlan_platform_kbuild_option))
+
+# Sourcing all files is for better incremental compilation.
+CNSS_SRC_FILES := \
+	$(wildcard $(LOCAL_PATH)/*) \
+	$(wildcard $(LOCAL_PATH)/*/*) \
+
+ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true)
+KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
+endif
+
+# Module.symvers needs to be generated as a intermediate module so that
+# other modules which depend on WLAN platform modules can set local
+# dependencies to it.
+
+########################### Module.symvers ############################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := wlan-platform-module-symvers
+LOCAL_MODULE_STEM         := Module.symvers
+LOCAL_MODULE_KBUILD_NAME  := Module.symvers
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+
+# Below are for Android build system to recognize each module name, so
+# they can be installed properly. Since Kbuild is used to compile these
+# modules, invoking any of them will cause other modules to be compiled
+# as well if corresponding flags are added in KBUILD_OPTIONS from upper
+# level Makefiles like wlan.mk.
+
+################################ cnss2 ################################
+include $(CLEAR_VARS)
+ifeq ($(TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE), true)
+LOCAL_REQUIRED_MODULES := sec-module-symvers
+LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
+endif #TARGET_KERNEL_DLKM_SECURE_MSM_OVERRIDE
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := cnss2.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss2/cnss2.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+######################## cnss_plat_ipc_qmi_svc ########################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := cnss_plat_ipc_qmi_svc.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss_utils/cnss_plat_ipc_qmi_svc.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+######################## wlan_firmware_service ########################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := wlan_firmware_service.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss_utils/wlan_firmware_service.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+############################### cnss_nl ###############################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := cnss_nl.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss_genl/cnss_nl.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+############################ cnss_prealloc ############################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := cnss_prealloc.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss_prealloc/cnss_prealloc.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+############################ cnss_utils ###############################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := cnss_utils.ko
+LOCAL_MODULE_KBUILD_NAME  := cnss_utils/cnss_utils.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+################################ icnss2 ################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES           := $(CNSS_SRC_FILES)
+LOCAL_MODULE              := icnss2.ko
+LOCAL_MODULE_KBUILD_NAME  := icnss2/icnss2.ko
+LOCAL_MODULE_TAGS         := optional
+LOCAL_MODULE_DEBUG_ENABLE := true
+LOCAL_MODULE_PATH         := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/Build_external_kernelmodule.mk
+endif #ENABLE_WLAN_PLATFORM_DLKM

+ 34 - 0
qcom/opensource/wlan/platform/BUILD.bazel

@@ -0,0 +1,34 @@
+load("//build/kernel/kleaf:kernel.bzl", "ddk_headers")
+load(":wlan_platform_modules.bzl", "define_modules")
+
+
+package(
+    default_visibility = [
+        "//visibility:public",
+    ],
+)
+
+ddk_headers(
+    name = "wlan-platform-headers",
+    hdrs = glob([
+        "inc/*.h",
+    ]),
+    includes = ["inc"],
+)
+
+ddk_headers(
+    name = "wlan-platform-private-headers",
+    hdrs = glob([
+        "cnss2/*.h",
+        "cnss_utils/*.h",
+        "icnss2/*.h"
+    ]),
+    includes = ["cnss2", "cnss_utils", "icnss2"],
+)
+
+ddk_headers(
+    name = "all-wlan-platform-headers",
+    hdrs = [":wlan-platform-headers", ":wlan-platform-private-headers"],
+)
+
+define_modules()

+ 103 - 0
qcom/opensource/wlan/platform/Kbuild

@@ -0,0 +1,103 @@
+ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS_OUT_OF_TREE
+endif
+
+ifeq ($(CONFIG_CNSS2_DEBUG),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_DEBUG
+endif
+
+ifeq ($(CONFIG_CNSS2_QMI),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_QMI
+endif
+
+ifeq ($(CONFIG_ONE_MSI_VECTOR),y)
+KBUILD_CPPFLAGS += -DCONFIG_ONE_MSI_VECTOR
+endif
+
+ifeq ($(CONFIG_ICNSS2_DEBUG),y)
+KBUILD_CPPFLAGS += -DCONFIG_ICNSS2_DEBUG
+endif
+
+ifeq ($(CONFIG_ICNSS2_QMI),y)
+KBUILD_CPPFLAGS += -DCONFIG_ICNSS2_QMI
+endif
+
+# CONFIG_WCNSS_MEM_PRE_ALLOC should never be "y" here since it
+# can be only compiled as a module from out-of-kernel-tree source.
+ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC),m)
+KBUILD_CPPFLAGS += -DCONFIG_WCNSS_MEM_PRE_ALLOC
+endif
+
+# CONFIG_CNSS_PLAT_IPC_QMI_SVC should never be "y" here since it
+# can be only compiled as a module from out-of-kernel-tree source.
+ifeq ($(CONFIG_CNSS_PLAT_IPC_QMI_SVC),m)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS_PLAT_IPC_QMI_SVC
+endif
+
+ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS_HW_SECURE_DISABLE
+endif
+
+ifeq ($(CONFIG_CNSS_HW_SECURE_SMEM), y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS_HW_SECURE_SMEM
+endif
+
+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
+
+ifeq ($(CONFIG_CNSS2_SSR_DRIVER_DUMP),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_SSR_DRIVER_DUMP
+endif
+
+ifeq ($(CONFIG_FREE_M3_BLOB_MEM),y)
+KBUILD_CPPFLAGS += -DCONFIG_FREE_M3_BLOB_MEM
+endif
+
+ifeq ($(CONFIG_DISABLE_CNSS_SRAM_DUMP),y)
+KBUILD_CPPFLAGS += -DCONFIG_DISABLE_CNSS_SRAM_DUMP
+endif
+
+ifeq ($(CONFIG_CNSS2_SMMU_DB_SUPPORT),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_SMMU_DB_SUPPORT
+endif
+
+ifeq ($(CONFIG_CNSS2_ENUM_WITH_LOW_SPEED),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_ENUM_WITH_LOW_SPEED
+endif
+
+ifeq ($(CONFIG_SLATE_MODULE_ENABLED), y)
+KBUILD_CPPFLAGS += -DCONFIG_SLATE_MODULE_ENABLED
+endif
+
+ifeq ($(CONFIG_FEATURE_SMEM_MAILBOX), y)
+KBUILD_CPPFLAGS += -DCONFIG_FEATURE_SMEM_MAILBOX
+endif
+
+found = $(shell if grep -qF "int msm_pcie_dsp_link_control" $(srctree)/include/linux/msm_pcie.h; then echo "yes" ;else echo "no" ;fi;)
+ifeq ($(findstring yes, $(found)), yes)
+KBUILD_CPPFLAGS += -DCONFIG_PCIE_SWITCH_SUPPORT
+endif
+
+found = $(shell if grep -qF "int msm_pcie_retrain_port_link" $(srctree)/include/linux/msm_pcie.h; then echo "yes" ;else echo "no" ;fi;)
+ifeq ($(findstring yes, $(found)), yes)
+KBUILD_CPPFLAGS += -DCONFIG_PCIE_SWITCH_RETRAIN_LINK_SUPPORT
+endif
+
+obj-$(CONFIG_CNSS2) += cnss2/
+obj-$(CONFIG_ICNSS2) += icnss2/
+obj-$(CONFIG_CNSS_GENL) += cnss_genl/
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
+obj-y += cnss_utils/

+ 48 - 0
qcom/opensource/wlan/platform/Makefile

@@ -0,0 +1,48 @@
+KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
+M ?= $(shell pwd)
+
+# $(WLAN_PLATFORM_ROOT) has to be a absolute path
+ifeq ($(WLAN_PLATFORM_ROOT),)
+WLAN_PLATFORM_ROOT = $(shell pwd)
+
+# If it reaches here, compilation is probably without Android.mk,
+# so enable all flags (including debug flag CONFIG_CNSS2_DEBUG) by
+# default.
+KBUILD_OPTIONS := WLAN_PLATFORM_ROOT=$(WLAN_PLATFORM_ROOT)
+ifeq ($(WLAN_BASEMACHINE),qcs40x)
+KBUILD_OPTIONS += CONFIG_CNSS_OUT_OF_TREE=y
+KBUILD_OPTIONS += CONFIG_ICNSS2=m
+KBUILD_OPTIONS += CONFIG_ICNSS2_QMI=y
+KBUILD_OPTIONS += CONFIG_ICNSS2_DEBUG=y
+KBUILD_OPTIONS += CONFIG_CNSS_QMI_SVC=m
+KBUILD_OPTIONS += CONFIG_WCNSS_MEM_PRE_ALLOC=m
+KBUILD_OPTIONS += CONFIG_CNSS_UTILS=m
+KBUILD_OPTIONS += CONFIG_CNSS_GENL=m
+KBUILD_OPTIONS += CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+else ifeq ($(USE_EXTERNAL_CONFIGS),)
+KBUILD_OPTIONS += CONFIG_CNSS_OUT_OF_TREE=y
+KBUILD_OPTIONS += CONFIG_CNSS2=m
+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
+KBUILD_OPTIONS += CONFIG_CNSS_GENL=m
+KBUILD_OPTIONS += CONFIG_WCNSS_MEM_PRE_ALLOC=m
+KBUILD_OPTIONS += CONFIG_CNSS_UTILS=m
+KBUILD_OPTIONS += CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+endif
+endif
+
+all: modules
+
+%:
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
+
+modules_install:
+	$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
+
+clean:
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) clean

+ 181 - 0
qcom/opensource/wlan/platform/cnss2/Kconfig

@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config CNSS2
+	tristate "CNSS2 Platform Driver for Wi-Fi Module"
+	depends on !CNSS && PCI_MSM
+	select CNSS_PLAT_IPC_QMI_SVC
+	help
+	  This module adds the support for Connectivity Subsystem (CNSS) used
+	  for PCIe based Wi-Fi devices with QCA6174/QCA6290 chipsets.
+	  This driver also adds support to integrate WLAN module to subsystem
+	  restart framework.
+
+config CNSS2_DEBUG
+	bool "CNSS2 Platform Driver Debug Support"
+	depends on CNSS2
+	help
+	  This option is to enable CNSS2 platform driver debug support which
+	  primarily includes providing additional verbose logs for certain
+	  features, enabling kernel panic for certain cases to aid the
+	  debugging, and enabling any other debug mechanisms.
+
+config CNSS2_QMI
+	bool "CNSS2 Platform Driver QMI support"
+	select CNSS_QMI_SVC
+	depends on CNSS2
+	help
+	  CNSS2 platform driver uses QMI framework to communicate with WLAN
+	  firmware. It sends and receives boot handshake messages to WLAN
+	  firmware, which includes hardware and software capabilities and
+	  configurations. It also sends WLAN on/off control message to
+	  firmware over QMI channel.
+
+config CNSS_ASYNC
+	bool "Enable/disable CNSS platform driver asynchronous probe"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver would do asynchronous probe.
+	  Using asynchronous probe will allow CNSS platform driver to
+	  probe in parallel with other device drivers and will help to
+	  reduce kernel boot time.
+
+config BUS_AUTO_SUSPEND
+	bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+	depends on CNSS2
+	depends on PCI
+	help
+	  Runtime Power Management is supported for PCIe based WLAN Drivers.
+	  The features enable cld wlan driver to suspend pcie bus when APPS
+	  is awake based on the driver inactivity with the Firmware.
+	  The Feature uses runtime power management framework from kernel to
+	  track bus access clients and to synchronize the driver activity
+	  during system pm.
+	  This config flag controls the feature per target based. The feature
+	  requires CNSS driver support.
+
+config CNSS_QCA6290
+	bool "Enable CNSS QCA6290 chipset specific changes"
+	depends on CNSS2
+	help
+	  This enables the changes from WLAN host driver that are specific to
+	  CNSS QCA6290 chipset.
+	  These changes are needed to support the new hardware architecture
+	  for CNSS QCA6290 chipset.
+
+config CNSS_QCA6390
+	bool "Enable CNSS QCA6390 chipset specific changes"
+	depends on CNSS2
+	help
+	  This enables the changes from WLAN host driver that are specific to
+	  CNSS QCA6390 chipset.
+	  These changes are needed to support the new hardware architecture
+	  for CNSS QCA6390 chipset.
+
+config CNSS_EMULATION
+	bool "Enable specific changes for emulation hardware"
+	depends on CNSS2
+	help
+	  This enables the changes from WLAN drivers that are specific to
+	  emulation hardware.
+	  These changes are needed for WLAN drivers to support and meet the
+	  requirement of emulation hardware.
+
+config CNSS_QCA6490
+	bool "Enable CNSS QCA6490 chipset specific changes"
+	depends on CNSS2
+	help
+	  This enables the changes from WLAN host driver that are specific to
+	  CNSS QCA6490 chipset.
+	  These changes are needed to support the new hardware architecture
+	  for CNSS QCA6490 chipset.
+
+config CNSS_REQ_FW_DIRECT
+	bool "Enable request_firmware_direct for firmware or configuration file"
+	depends on CNSS2
+	help
+	  This enables calling request_firmware_direct for firmware or
+	  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
+	depends on PCI
+	help
+	  Conditional pcie bus suspend and device powering off for wlan after
+	  driver probe for the first time.
+	  With this feature enabled, pcie bus suspend and device powering off
+	  will not take place for certain wlan chipsets after driver probing
+	  for the first time to avoid potential subsequent failures during
+	  device re-probe(after wlan function driver loaded) under very bad
+	  thermal conditions.
+
+config DISABLE_CNSS_SRAM_DUMP
+	bool "Disable sram_dump"
+	depends on CNSS2
+	depends on CNSS2_DEBUG
+	help
+	  If enabled, CNSS plafrom driver will not dump sram when MHI power on
+	  timeout for CNSS QCA6490 chipset only. Since this feature about
+	  sram dump costs 4M memory.
+
+config CNSS2_SMMU_DB_SUPPORT
+	bool "Enable early trace stop support"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver will notify wlan fw to stop
+	  traces by ringing MHI host doorbell register. This feature helps
+	  to get traces which contain smmu fault address and enables
+	  debugging.
+
+config CNSS_HW_SECURE_DISABLE
+	bool "Enable HW secure disable"
+	depends on CNSS2
+	help
+	  If enabled, WLAN HW can be securely disabled. It would be able to
+	  handle WLAN cold boot initialization sequence changes if HW is
+	  disabled at boot and WLAN resume sequence after WLAN HW is enabled.
+
+config CNSS_HW_SECURE_SMEM
+	bool "Enable SMEM API based HW peripheral security"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver will use SMEM APIs intead of SCM
+	  APIs to check peripheral secure state of HW.
+
+config CNSS2_SSR_DRIVER_DUMP
+	bool "Enable Host SSR DRIVER DUMP Collection"
+	depends on CNSS2
+	help
+	  If enabled, host driver dump will be collected upon SSR.
+
+config CNSS_OUT_OF_TREE
+	bool "Enable Out of Tree Usage"
+	depends on CNSS2
+	help
+	  If enabled, CNSS platform driver modules would be able to access
+	  functions from the other modules in the platform driver.
+
+config WCNSS_MEM_PRE_ALLOC
+	tristate "WCNSS pre-alloc memory support"
+	help
+	  Pre-allocate memory for the WLAN driver module.
+	  This feature enable cld wlan driver to use pre allocated memory
+	  for it's internal usage and release it to back to pre allocated pool.
+	  This memory is allocated at the cold boot time.
+
+config CNSS2_ENUM_WITH_LOW_SPEED
+	bool "Enable/Disable enumurate with low speed feature"
+	depends on CNSS2
+	depends on PCI
+	help
+	  Set link target speed to Gen1 before enum, and then restore default
+	  RC speed to re-establish link speed. For Genoa chip, needn't restore.

+ 28 - 0
qcom/opensource/wlan/platform/cnss2/Makefile

@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ccflags-y += -Wmissing-prototypes
+
+ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
+else
+ccflags-y += -I$(srctree)/drivers/net/wireless/cnss_utils
+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/
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/../../securemsm-kernel/include/uapi/linux/
+endif
+
+obj-$(CONFIG_CNSS2) += cnss2.o
+
+cnss2-y := main.o
+cnss2-y += bus.o
+cnss2-y += debug.o
+cnss2-y += pci.o
+cnss2-y += power.o
+cnss2-y += genl.o
+cnss2-$(CONFIG_PCI_MSM) += pci_qcom.o
+cnss2-$(CONFIG_CNSS2_QMI) += qmi.o coexistence_service_v01.o

+ 10 - 0
qcom/opensource/wlan/platform/cnss2/anorak_consolidate_defconfig

@@ -0,0 +1,10 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS2_DEBUG=y

+ 9 - 0
qcom/opensource/wlan/platform/cnss2/anorak_gki_defconfig

@@ -0,0 +1,9 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 868 - 0
qcom/opensource/wlan/platform/cnss2/bus.c

@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "bus.h"
+#include "debug.h"
+#include "pci.h"
+#include "pci_platform.h"
+
+enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
+{
+	if (!dev)
+		return CNSS_BUS_NONE;
+
+	if (!dev->bus)
+		return CNSS_BUS_NONE;
+
+	if (memcmp(dev->bus->name, "pci", 3) == 0)
+		return CNSS_BUS_PCI;
+	else
+		return CNSS_BUS_NONE;
+}
+
+enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+	struct device *dev;
+	u32 bus_type_dt = CNSS_BUS_NONE;
+
+	if (plat_priv->dt_type == CNSS_DTT_MULTIEXCHG) {
+		dev = &plat_priv->plat_dev->dev;
+		ret = of_property_read_u32(dev->of_node, "qcom,bus-type",
+					   &bus_type_dt);
+		if (!ret)
+			if (bus_type_dt < CNSS_BUS_MAX)
+				cnss_pr_dbg("Got bus type[%u] from dt\n",
+					    bus_type_dt);
+			else
+				bus_type_dt = CNSS_BUS_NONE;
+		else
+			cnss_pr_err("No bus type for multi-exchg dt\n");
+
+		return bus_type_dt;
+	}
+
+	switch (plat_priv->device_id) {
+	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:
+	case PEACH_DEVICE_ID:
+		return CNSS_BUS_PCI;
+	default:
+		cnss_pr_err("Unknown device_id: 0x%lx\n", plat_priv->device_id);
+		return CNSS_BUS_NONE;
+	}
+}
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev)
+{
+	if (!dev)
+		return NULL;
+
+	switch (cnss_get_dev_bus_type(dev)) {
+	case CNSS_BUS_PCI:
+		return cnss_get_pci_priv(to_pci_dev(dev));
+	default:
+		return NULL;
+	}
+}
+
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
+{
+	void *bus_priv;
+
+	if (!dev)
+		return cnss_get_plat_priv(NULL);
+
+	bus_priv = cnss_bus_dev_to_bus_priv(dev);
+	if (!bus_priv)
+		return NULL;
+
+	switch (cnss_get_dev_bus_type(dev)) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_priv_to_plat_priv(bus_priv);
+	default:
+		return NULL;
+	}
+}
+
+int cnss_bus_init(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_init(plat_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+void cnss_bus_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_deinit(plat_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+void cnss_bus_add_fw_prefix_name(struct cnss_plat_data *plat_priv,
+				 char *prefix_name, char *name)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_add_fw_prefix_name(plat_priv->bus_priv,
+						   prefix_name, name);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+int cnss_bus_load_tme_patch(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_load_tme_patch(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_load_tme_opt_file(struct cnss_plat_data *plat_priv,
+				enum wlfw_tme_lite_file_type_v01 file)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_load_tme_opt_file(plat_priv->bus_priv, file);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_load_m3(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_load_m3(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_load_aux(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_load_aux(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_handle_dev_sol_irq(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_handle_dev_sol_irq(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_alloc_qdss_mem(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		cnss_pci_free_qdss_mem(plat_priv->bus_priv);
+		return;
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_get_wake_msi(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_force_fw_assert_hdlr(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_qmi_send_get(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_qmi_send_get(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_qmi_send_put(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_qmi_send_put(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+void cnss_bus_fw_boot_timeout_hdlr(struct timer_list *t)
+{
+	struct cnss_plat_data *plat_priv =
+		from_timer(plat_priv, t, fw_boot_timer);
+
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv, bool in_panic)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_collect_dump_info(plat_priv->bus_priv,
+						  in_panic);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+void cnss_bus_device_crashed(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_device_crashed(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return;
+	}
+}
+
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_call_driver_probe(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_call_driver_remove(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dev_powerup(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dev_shutdown(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dev_crash_shutdown(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dev_ramdump(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_runtime_pm_get_sync(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_pm_runtime_get_sync(plat_priv->bus_priv, RTPM_ID_CNSS);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+void cnss_bus_runtime_pm_put(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		cnss_pci_pm_runtime_mark_last_busy(plat_priv->bus_priv);
+		cnss_pci_pm_runtime_put_autosuspend(plat_priv->bus_priv, RTPM_ID_CNSS);
+		break;
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+	}
+}
+
+int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
+				      int modem_current_status)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_call_driver_modem_status(plat_priv->bus_priv,
+							 modem_current_status);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_status status)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_update_status(plat_priv->bus_priv, status);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_update_uevent(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_status status, void *data)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_call_driver_uevent(plat_priv->bus_priv,
+						   status, data);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pcie_is_device_down(plat_priv->bus_priv);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return 0;
+	}
+}
+
+int cnss_bus_shutdown_cleanup(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_shutdown_cleanup(plat_priv->bus_priv);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return 0;
+	}
+}
+
+int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_check_link_status(plat_priv->bus_priv);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return 0;
+	}
+}
+
+int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_recover_link_down(plat_priv->bus_priv);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset,
+			    u32 *val, bool raw_access)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_debug_reg_read(plat_priv->bus_priv, offset,
+					       val, raw_access);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return 0;
+	}
+}
+
+int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset,
+			     u32 val, bool raw_access)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_debug_reg_write(plat_priv->bus_priv, offset,
+						val, raw_access);
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return 0;
+	}
+}
+
+int cnss_bus_get_iova(struct cnss_plat_data *plat_priv, u64 *addr, u64 *size)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_get_iova(plat_priv->bus_priv, addr, size);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_get_iova_ipa(struct cnss_plat_data *plat_priv, u64 *addr,
+			  u64 *size)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_get_iova_ipa(plat_priv->bus_priv, addr, size);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+bool cnss_bus_is_smmu_s1_enabled(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return false;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_is_smmu_s1_enabled(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return false;
+	}
+}
+
+int cnss_bus_dsp_link_control(struct cnss_plat_data *plat_priv,
+			      bool link_enable)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dsp_link_control(plat_priv->bus_priv, link_enable);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_set_dsp_link_status(struct cnss_plat_data *plat_priv,
+				 bool link_enable)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_set_dsp_link_status(plat_priv->bus_priv, link_enable);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_get_dsp_link_status(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_get_dsp_link_status(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_dsp_link_enable(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv || plat_priv->pcie_switch_type != PCIE_SWITCH_NTN3)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_dsp_link_enable(plat_priv->bus_priv);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+int cnss_bus_update_time_sync_period(struct cnss_plat_data *plat_priv,
+				     unsigned int time_sync_period)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_update_time_sync_period(plat_priv->bus_priv,
+							time_sync_period);
+	default:
+		cnss_pr_err("Unsupported bus type: %d\n",
+			    plat_priv->bus_type);
+		return -EINVAL;
+	}
+}
+
+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)
+{
+	struct cnss_pci_data *pci_priv;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv) {
+		cnss_pr_err("mhi satellite could not be disabled since pci_priv is NULL\n");
+		return;
+	}
+
+	switch (plat_priv->bus_type) {
+	case CNSS_BUS_PCI:
+		/* MHI satellite configuration is only for KIWI V2 and
+		 * that too only in DRV mode.
+		 */
+		if (plat_priv->device_id == KIWI_DEVICE_ID &&
+		    plat_priv->device_version.major_version == FW_V2_NUMBER) {
+			cnss_pr_dbg("Remove MHI satellite configuration\n");
+			return cnss_mhi_controller_set_base(pci_priv, 0);
+		}
+		break;
+	default:
+		cnss_pr_dbg("Unsupported bus type: %d, ignore disable mhi satellite cfg\n",
+			    plat_priv->bus_type);
+		return;
+	}
+
+	return;
+}
+#else
+void cnss_bus_disable_mhi_satellite_cfg(struct cnss_plat_data *pci_priv)
+{
+}
+#endif

+ 86 - 0
qcom/opensource/wlan/platform/cnss2/bus.h

@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CNSS_BUS_H
+#define _CNSS_BUS_H
+
+#include "main.h"
+
+#define QCA6174_REV_ID_OFFSET		0x08
+#define QCA6174_REV3_VERSION		0x5020000
+#define QCA6174_REV3_2_VERSION		0x5030000
+
+enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev);
+enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv);
+void *cnss_bus_dev_to_bus_priv(struct device *dev);
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+int cnss_bus_init(struct cnss_plat_data *plat_priv);
+void cnss_bus_deinit(struct cnss_plat_data *plat_priv);
+void cnss_bus_add_fw_prefix_name(struct cnss_plat_data *plat_priv,
+				 char *prefix_name, char *name);
+int cnss_bus_load_tme_patch(struct cnss_plat_data *plat_priv);
+int cnss_bus_load_tme_opt_file(struct cnss_plat_data *plat_priv,
+				enum wlfw_tme_lite_file_type_v01 file);
+int cnss_bus_runtime_pm_get_sync(struct cnss_plat_data *plat_priv);
+void cnss_bus_runtime_pm_put(struct cnss_plat_data *plat_priv);
+int cnss_bus_load_m3(struct cnss_plat_data *plat_priv);
+int cnss_bus_load_aux(struct cnss_plat_data *plat_priv);
+int cnss_bus_handle_dev_sol_irq(struct cnss_plat_data *plat_priv);
+int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv);
+int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv);
+void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv);
+u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv);
+int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv);
+int cnss_bus_qmi_send_get(struct cnss_plat_data *plat_priv);
+int cnss_bus_qmi_send_put(struct cnss_plat_data *plat_priv);
+void cnss_bus_fw_boot_timeout_hdlr(struct timer_list *t);
+void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv,
+				bool in_panic);
+void cnss_bus_device_crashed(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv);
+int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data);
+int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv);
+int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
+				      int modem_current_status);
+int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_status status);
+int cnss_bus_update_uevent(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_status status, void *data);
+int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv);
+int cnss_bus_shutdown_cleanup(struct cnss_plat_data *plat_priv);
+int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv);
+int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv);
+int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset,
+			    u32 *val, bool raw_access);
+int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset,
+			     u32 val, bool raw_access);
+int cnss_bus_get_iova(struct cnss_plat_data *plat_priv, u64 *addr, u64 *size);
+int cnss_bus_get_iova_ipa(struct cnss_plat_data *plat_priv, u64 *addr,
+			  u64 *size);
+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);
+int cnss_bus_dsp_link_control(struct cnss_plat_data *plat_priv,
+			      bool link_enable);
+int cnss_bus_set_dsp_link_status(struct cnss_plat_data *plat_priv,
+				 bool link_enable);
+int cnss_bus_get_dsp_link_status(struct cnss_plat_data *plat_priv);
+int cnss_bus_dsp_link_enable(struct cnss_plat_data *plat_priv);
+#endif /* _CNSS_BUS_H */

+ 100 - 0
qcom/opensource/wlan/platform/cnss2/coexistence_service_v01.c

@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */
+
+#include <linux/soc/qcom/qmi.h>
+
+#include "coexistence_service_v01.h"
+
+struct qmi_elem_info coex_antenna_switch_to_wlan_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+				coex_antenna_switch_to_wlan_req_msg_v01,
+				antenna),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct qmi_elem_info coex_antenna_switch_to_wlan_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
+				coex_antenna_switch_to_wlan_resp_msg_v01,
+				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
+				coex_antenna_switch_to_wlan_resp_msg_v01,
+				grant_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+				coex_antenna_switch_to_wlan_resp_msg_v01,
+				grant),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct qmi_elem_info coex_antenna_switch_to_mdm_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+				coex_antenna_switch_to_mdm_req_msg_v01,
+				antenna),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct qmi_elem_info coex_antenna_switch_to_mdm_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
+				coex_antenna_switch_to_mdm_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,
+	},
+};

+ 52 - 0
qcom/opensource/wlan/platform/cnss2/coexistence_service_v01.h

@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved. */
+
+#ifndef COEXISTENCE_SERVICE_V01_H
+#define COEXISTENCE_SERVICE_V01_H
+
+#define COEX_SERVICE_ID_V01 0x22
+#define COEX_SERVICE_VERS_V01 0x01
+
+#define COEX_SERVICE_MAX_MSG_LEN 8204
+
+#define QMI_COEX_SWITCH_ANTENNA_TO_WLAN_RESP_V01 0x0042
+#define QMI_COEX_SWITCH_ANTENNA_TO_WLAN_REQ_V01 0x0042
+#define QMI_COEX_SWITCH_ANTENNA_TO_MDM_RESP_V01 0x0042
+#define QMI_COEX_SWITCH_ANTENNA_TO_MDM_REQ_V01 0x0042
+
+#define COEX_ANTENNA_BAND_2GHZ_CHAIN0_V01 ((u64)0x0000000000000001ULL)
+#define COEX_ANTENNA_BAND_2GHZ_CHAIN1_V01 ((u64)0x0000000000000002ULL)
+#define COEX_ANTENNA_BAND_5GHZ_CHAIN0_V01 ((u64)0x0000000000000004ULL)
+#define COEX_ANTENNA_BAND_5GHZ_CHAIN1_V01 ((u64)0x0000000000000008ULL)
+
+struct coex_antenna_switch_to_wlan_req_msg_v01 {
+	u64 antenna;
+};
+
+#define COEX_ANTENNA_SWITCH_TO_WLAN_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info coex_antenna_switch_to_wlan_req_msg_v01_ei[];
+
+struct coex_antenna_switch_to_wlan_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 grant_valid;
+	u64 grant;
+};
+
+#define COEX_ANTENNA_SWITCH_TO_WLAN_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info coex_antenna_switch_to_wlan_resp_msg_v01_ei[];
+
+struct coex_antenna_switch_to_mdm_req_msg_v01 {
+	u64 antenna;
+};
+
+#define COEX_ANTENNA_SWITCH_TO_MDM_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info coex_antenna_switch_to_mdm_req_msg_v01_ei[];
+
+struct coex_antenna_switch_to_mdm_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define COEX_ANTENNA_SWITCH_TO_MDM_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info coex_antenna_switch_to_mdm_resp_msg_v01_ei[];
+
+#endif

+ 1222 - 0
qcom/opensource/wlan/platform/cnss2/debug.c

@@ -0,0 +1,1222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include "main.h"
+#include "bus.h"
+#include "debug.h"
+#include "pci.h"
+
+#define MMIO_REG_ACCESS_MEM_TYPE		0xFF
+#define MMIO_REG_RAW_ACCESS_MEM_TYPE		0xFE
+#define DEFAULT_KERNEL_LOG_LEVEL		INFO_LOG
+#define DEFAULT_IPC_LOG_LEVEL			DEBUG_LOG
+
+enum log_level cnss_kernel_log_level = DEFAULT_KERNEL_LOG_LEVEL;
+
+#if IS_ENABLED(CONFIG_IPC_LOGGING)
+void *cnss_ipc_log_context;
+void *cnss_ipc_log_long_context;
+enum log_level cnss_ipc_log_level = DEFAULT_IPC_LOG_LEVEL;
+
+static int cnss_set_ipc_log_level(u32 val)
+{
+	if (val < MAX_LOG) {
+		cnss_ipc_log_level = val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static u32 cnss_get_ipc_log_level(void)
+{
+	return cnss_ipc_log_level;
+}
+#else
+static int cnss_set_ipc_log_level(int val) { return -EINVAL; }
+static u32 cnss_get_ipc_log_level(void) { return MAX_LOG; }
+#endif
+
+static int cnss_pin_connect_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *cnss_priv = s->private;
+
+	seq_puts(s, "Pin connect results\n");
+	seq_printf(s, "FW power pin result: %04x\n",
+		   cnss_priv->pin_result.fw_pwr_pin_result);
+	seq_printf(s, "FW PHY IO pin result: %04x\n",
+		   cnss_priv->pin_result.fw_phy_io_pin_result);
+	seq_printf(s, "FW RF pin result: %04x\n",
+		   cnss_priv->pin_result.fw_rf_pin_result);
+	seq_printf(s, "Host pin result: %04x\n",
+		   cnss_priv->pin_result.host_pin_result);
+	seq_puts(s, "\n");
+
+	return 0;
+}
+
+static int cnss_pin_connect_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_pin_connect_show, inode->i_private);
+}
+
+static const struct file_operations cnss_pin_connect_fops = {
+	.read		= seq_read,
+	.release	= single_release,
+	.open		= cnss_pin_connect_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static u64 cnss_get_serial_id(struct cnss_plat_data *plat_priv)
+{
+	u32 msb = plat_priv->serial_id.serial_id_msb;
+	u32 lsb = plat_priv->serial_id.serial_id_lsb;
+
+	msb &= 0xFFFF;
+	return (((u64)msb << 32) | lsb);
+}
+
+static int cnss_stats_show_state(struct seq_file *s,
+				 struct cnss_plat_data *plat_priv)
+{
+	enum cnss_driver_state i;
+	int skip = 0;
+	unsigned long state;
+
+	seq_printf(s, "\nSerial Number: 0x%llx",
+		   cnss_get_serial_id(plat_priv));
+	seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
+	for (i = 0, state = plat_priv->driver_state; state != 0;
+	     state >>= 1, i++) {
+		if (!(state & 0x1))
+			continue;
+
+		if (skip++)
+			seq_puts(s, " | ");
+
+		switch (i) {
+		case CNSS_QMI_WLFW_CONNECTED:
+			seq_puts(s, "QMI_WLFW_CONNECTED");
+			continue;
+		case CNSS_FW_MEM_READY:
+			seq_puts(s, "FW_MEM_READY");
+			continue;
+		case CNSS_FW_READY:
+			seq_puts(s, "FW_READY");
+			continue;
+		case CNSS_IN_COLD_BOOT_CAL:
+			seq_puts(s, "IN_COLD_BOOT_CAL");
+			continue;
+		case CNSS_DRIVER_LOADING:
+			seq_puts(s, "DRIVER_LOADING");
+			continue;
+		case CNSS_DRIVER_UNLOADING:
+			seq_puts(s, "DRIVER_UNLOADING");
+			continue;
+		case CNSS_DRIVER_IDLE_RESTART:
+			seq_puts(s, "IDLE_RESTART");
+			continue;
+		case CNSS_DRIVER_IDLE_SHUTDOWN:
+			seq_puts(s, "IDLE_SHUTDOWN");
+			continue;
+		case CNSS_DRIVER_PROBED:
+			seq_puts(s, "DRIVER_PROBED");
+			continue;
+		case CNSS_DRIVER_RECOVERY:
+			seq_puts(s, "DRIVER_RECOVERY");
+			continue;
+		case CNSS_FW_BOOT_RECOVERY:
+			seq_puts(s, "FW_BOOT_RECOVERY");
+			continue;
+		case CNSS_DEV_ERR_NOTIFY:
+			seq_puts(s, "DEV_ERR");
+			continue;
+		case CNSS_DRIVER_DEBUG:
+			seq_puts(s, "DRIVER_DEBUG");
+			continue;
+		case CNSS_COEX_CONNECTED:
+			seq_puts(s, "COEX_CONNECTED");
+			continue;
+		case CNSS_IMS_CONNECTED:
+			seq_puts(s, "IMS_CONNECTED");
+			continue;
+		case CNSS_IN_SUSPEND_RESUME:
+			seq_puts(s, "IN_SUSPEND_RESUME");
+			continue;
+		case CNSS_IN_REBOOT:
+			seq_puts(s, "IN_REBOOT");
+			continue;
+		case CNSS_COLD_BOOT_CAL_DONE:
+			seq_puts(s, "COLD_BOOT_CAL_DONE");
+			continue;
+		case CNSS_IN_PANIC:
+			seq_puts(s, "IN_PANIC");
+			continue;
+		case CNSS_QMI_DEL_SERVER:
+			seq_puts(s, "DEL_SERVER_IN_PROGRESS");
+			continue;
+		case CNSS_QMI_DMS_CONNECTED:
+			seq_puts(s, "DMS_CONNECTED");
+			continue;
+		case CNSS_DMS_DEL_SERVER:
+			seq_puts(s, "DMS_DEL_SERVER");
+			continue;
+		case CNSS_DAEMON_CONNECTED:
+			seq_puts(s, "DAEMON_CONNECTED");
+			continue;
+		case CNSS_PCI_PROBE_DONE:
+			seq_puts(s, "PCI PROBE DONE");
+			continue;
+		case CNSS_DRIVER_REGISTER:
+			seq_puts(s, "DRIVER REGISTERED");
+			continue;
+		case CNSS_WLAN_HW_DISABLED:
+			seq_puts(s, "WLAN HW DISABLED");
+			continue;
+		case CNSS_FS_READY:
+			seq_puts(s, "FS READY");
+			continue;
+		case CNSS_DRIVER_REGISTERED:
+			seq_puts(s, "DRIVER REGISTERED");
+			continue;
+		case CNSS_POWER_OFF:
+			seq_puts(s, "POWER OFF");
+			continue;
+		}
+
+		seq_printf(s, "UNKNOWN-%d", i);
+	}
+	seq_puts(s, ")\n");
+
+	return 0;
+}
+
+static int cnss_stats_show_gpio_state(struct seq_file *s,
+				      struct cnss_plat_data *plat_priv)
+{
+	seq_printf(s, "\nHost SOL: %d", cnss_get_host_sol_value(plat_priv));
+	seq_printf(s, "\nDev SOL: %d", cnss_get_dev_sol_value(plat_priv));
+
+	return 0;
+}
+
+static int cnss_stats_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+
+	cnss_stats_show_state(s, plat_priv);
+	cnss_stats_show_gpio_state(s, plat_priv);
+
+	return 0;
+}
+
+static int cnss_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_stats_show, inode->i_private);
+}
+
+static const struct file_operations cnss_stats_fops = {
+	.read		= seq_read,
+	.release	= single_release,
+	.open		= cnss_stats_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static ssize_t cnss_dev_boot_debug_write(struct file *fp,
+					 const char __user *user_buf,
+					 size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	struct cnss_pci_data *pci_priv;
+	char buf[64];
+	char *cmd;
+	unsigned int len = 0;
+	char *sptr, *token;
+	const char *delim = " ";
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+	cmd = token;
+	cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
+
+	if (sysfs_streq(cmd, "on")) {
+		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")) {
+		ret = cnss_pci_init(plat_priv);
+	} else if (sysfs_streq(cmd, "powerup")) {
+		set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_POWER_UP,
+					     CNSS_EVENT_SYNC, NULL);
+	} else if (sysfs_streq(cmd, "shutdown")) {
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_POWER_DOWN,
+					     0, NULL);
+		clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+	} else if (sysfs_streq(cmd, "assert_host_sol")) {
+		pci_priv = plat_priv->bus_priv;
+		cnss_auto_resume(&pci_priv->pci_dev->dev);
+		ret = cnss_set_host_sol_value(plat_priv, 1);
+	} else if (sysfs_streq(cmd, "deassert_host_sol")) {
+		ret = cnss_set_host_sol_value(plat_priv, 0);
+	} else if (sysfs_streq(cmd, "pdc_update")) {
+		if (!sptr)
+			return -EINVAL;
+		ret = cnss_aop_send_msg(plat_priv, sptr);
+	} else if (sysfs_streq(cmd, "dev_check")) {
+		cnss_wlan_hw_disable_check(plat_priv);
+	} else if (sysfs_streq(cmd, "dev_enable")) {
+		cnss_wlan_hw_enable();
+	} else {
+		pci_priv = plat_priv->bus_priv;
+		if (!pci_priv)
+			return -ENODEV;
+
+		if (sysfs_streq(cmd, "download")) {
+			set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+			ret = cnss_pci_start_mhi(pci_priv);
+		} else if (sysfs_streq(cmd, "linkup")) {
+			ret = cnss_resume_pci_link(pci_priv);
+		} else if (sysfs_streq(cmd, "linkdown")) {
+			ret = cnss_suspend_pci_link(pci_priv);
+		} else if (sysfs_streq(cmd, "assert")) {
+			cnss_pr_info("FW Assert triggered for debug\n");
+			ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
+		} else if (sysfs_streq(cmd, "set_cbc_done")) {
+			cnss_pr_dbg("Force set cold boot cal done status\n");
+			set_bit(CNSS_COLD_BOOT_CAL_DONE,
+				&plat_priv->driver_state);
+		} else {
+			cnss_pr_err("Device boot debugfs command is invalid\n");
+			ret = -EINVAL;
+		}
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
+{
+	seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
+	seq_puts(s, "<action> can be one of below:\n");
+	seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
+	seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
+	seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
+	seq_puts(s, "download: download FW and do QMI handshake with FW\n");
+	seq_puts(s, "linkup: bring up PCIe link\n");
+	seq_puts(s, "linkdown: bring down PCIe link\n");
+	seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
+	seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
+	seq_puts(s, "assert: trigger firmware assert\n");
+	seq_puts(s, "set_cbc_done: Set cold boot calibration done status\n");
+	seq_puts(s, "\npdc_update usage:");
+	seq_puts(s, "1. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: <vreg>.<mode>, <seq>: <val>} > <debugfs_path>/cnss/dev_boot\n");
+	seq_puts(s, "2. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: pdc, enable: <val>} > <debugfs_path>/cnss/dev_boot\n");
+	seq_puts(s, "assert_host_sol: Assert host sol\n");
+	seq_puts(s, "deassert_host_sol: Deassert host sol\n");
+	seq_puts(s, "dev_check: Check whether HW is disabled or not\n");
+	seq_puts(s, "dev_enable: Enable HW\n");
+
+	return 0;
+}
+
+static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_dev_boot_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_dev_boot_debug_write,
+	.release	= single_release,
+	.open		= cnss_dev_boot_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+
+	mutex_lock(&plat_priv->dev_lock);
+	if (!plat_priv->diag_reg_read_buf) {
+		seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
+		seq_puts(s, "Use mem_type = 0xff for register read by IO access, data_len will be ignored\n");
+		seq_puts(s, "Use mem_type = 0xfe for register read by raw IO access which skips sanity checks, data_len will be ignored\n");
+		seq_puts(s, "Use other mem_type for register read by QMI\n");
+		mutex_unlock(&plat_priv->dev_lock);
+		return 0;
+	}
+
+	seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
+		   plat_priv->diag_reg_read_addr,
+		   plat_priv->diag_reg_read_mem_type,
+		   plat_priv->diag_reg_read_len);
+
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
+		     plat_priv->diag_reg_read_buf,
+		     plat_priv->diag_reg_read_len, false);
+
+	plat_priv->diag_reg_read_len = 0;
+	kfree(plat_priv->diag_reg_read_buf);
+	plat_priv->diag_reg_read_buf = NULL;
+	mutex_unlock(&plat_priv->dev_lock);
+
+	return 0;
+}
+
+static ssize_t cnss_reg_read_debug_write(struct file *fp,
+					 const char __user *user_buf,
+					 size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *sptr, *token;
+	unsigned int len = 0;
+	u32 reg_offset, mem_type;
+	u32 data_len = 0, reg_val = 0;
+	u8 *reg_buf = NULL;
+	const char *delim = " ";
+	int ret = 0;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &mem_type))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_offset))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &data_len))
+		return -EINVAL;
+
+	if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
+	    mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
+		ret = cnss_bus_debug_reg_read(plat_priv, reg_offset, &reg_val,
+					      mem_type ==
+					      MMIO_REG_RAW_ACCESS_MEM_TYPE);
+		if (ret)
+			return ret;
+		cnss_pr_dbg("Read 0x%x from register offset 0x%x\n", reg_val,
+			    reg_offset);
+		return count;
+	}
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&plat_priv->dev_lock);
+	kfree(plat_priv->diag_reg_read_buf);
+	plat_priv->diag_reg_read_buf = NULL;
+
+	reg_buf = kzalloc(data_len, GFP_KERNEL);
+	if (!reg_buf) {
+		mutex_unlock(&plat_priv->dev_lock);
+		return -ENOMEM;
+	}
+
+	ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
+					       mem_type, data_len,
+					       reg_buf);
+	if (ret) {
+		kfree(reg_buf);
+		mutex_unlock(&plat_priv->dev_lock);
+		return ret;
+	}
+
+	plat_priv->diag_reg_read_addr = reg_offset;
+	plat_priv->diag_reg_read_mem_type = mem_type;
+	plat_priv->diag_reg_read_len = data_len;
+	plat_priv->diag_reg_read_buf = reg_buf;
+	mutex_unlock(&plat_priv->dev_lock);
+
+	return count;
+}
+
+static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_reg_read_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_read_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_reg_read_debug_write,
+	.open		= cnss_reg_read_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
+{
+	seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
+	seq_puts(s, "Use mem_type = 0xff for register write by IO access\n");
+	seq_puts(s, "Use mem_type = 0xfe for register write by raw IO access which skips sanity checks\n");
+	seq_puts(s, "Use other mem_type for register write by QMI\n");
+
+	return 0;
+}
+
+static ssize_t cnss_reg_write_debug_write(struct file *fp,
+					  const char __user *user_buf,
+					  size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *sptr, *token;
+	unsigned int len = 0;
+	u32 reg_offset, mem_type, reg_val;
+	const char *delim = " ";
+	int ret = 0;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &mem_type))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_offset))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_val))
+		return -EINVAL;
+
+	if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
+	    mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
+		ret = cnss_bus_debug_reg_write(plat_priv, reg_offset, reg_val,
+					       mem_type ==
+					       MMIO_REG_RAW_ACCESS_MEM_TYPE);
+		if (ret)
+			return ret;
+		cnss_pr_dbg("Wrote 0x%x to register offset 0x%x\n", reg_val,
+			    reg_offset);
+		return count;
+	}
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return -EINVAL;
+	}
+
+	ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
+						sizeof(u32),
+						(u8 *)&reg_val);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_reg_write_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_write_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_reg_write_debug_write,
+	.open		= cnss_reg_write_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
+					   const char __user *user_buf,
+					   size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	struct cnss_pci_data *pci_priv;
+	char buf[64];
+	char *cmd;
+	unsigned int len = 0;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv)
+		return -ENODEV;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	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")) {
+		ret = cnss_pci_pm_request_resume(pci_priv);
+	} else if (sysfs_streq(cmd, "resume")) {
+		ret = cnss_pci_pm_runtime_resume(pci_priv);
+	} else if (sysfs_streq(cmd, "get")) {
+		ret = cnss_pci_pm_runtime_get(pci_priv, RTPM_ID_CNSS);
+	} else if (sysfs_streq(cmd, "get_noresume")) {
+		cnss_pci_pm_runtime_get_noresume(pci_priv, RTPM_ID_CNSS);
+	} else if (sysfs_streq(cmd, "put_autosuspend")) {
+		ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv,
+							  RTPM_ID_CNSS);
+	} else if (sysfs_streq(cmd, "put_noidle")) {
+		cnss_pci_pm_runtime_put_noidle(pci_priv, RTPM_ID_CNSS);
+	} else if (sysfs_streq(cmd, "mark_last_busy")) {
+		cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+	} else if (sysfs_streq(cmd, "resume_bus")) {
+		cnss_pci_resume_bus(pci_priv);
+	} else if (sysfs_streq(cmd, "suspend_bus")) {
+		cnss_pci_suspend_bus(pci_priv);
+	} else {
+		cnss_pr_err("Runtime PM debugfs command is invalid\n");
+		ret = -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+	struct cnss_pci_data *pci_priv;
+	int i;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv)
+		return -ENODEV;
+
+	seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
+	seq_puts(s, "<action> can be one of below:\n");
+	seq_puts(s, "usage_count: get runtime PM usage count\n");
+	seq_puts(s, "reques_resume: do async runtime PM resume\n");
+	seq_puts(s, "resume: do sync runtime PM resume\n");
+	seq_puts(s, "get: do runtime PM get\n");
+	seq_puts(s, "get_noresume: do runtime PM get noresume\n");
+	seq_puts(s, "put_noidle: do runtime PM put noidle\n");
+	seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
+	seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
+	seq_puts(s, "resume_bus: do bus resume only\n");
+	seq_puts(s, "suspend_bus: do bus suspend only\n");
+
+	seq_puts(s, "\nStats:\n");
+	seq_printf(s, "%s: %u\n", "get count",
+		   atomic_read(&pci_priv->pm_stats.runtime_get));
+	seq_printf(s, "%s: %u\n", "put count",
+		   atomic_read(&pci_priv->pm_stats.runtime_put));
+	seq_printf(s, "%-10s%-10s%-10s%-15s%-15s\n",
+		   "id:", "get",  "put", "get time(us)", "put time(us)");
+	for (i = 0; i < RTPM_ID_MAX; i++) {
+		seq_printf(s, "%d%-9s", i, ":");
+		seq_printf(s, "%-10d",
+			   atomic_read(&pci_priv->pm_stats.runtime_get_id[i]));
+		seq_printf(s, "%-10d",
+			   atomic_read(&pci_priv->pm_stats.runtime_put_id[i]));
+		seq_printf(s, "%-15llu",
+			   pci_priv->pm_stats.runtime_get_timestamp_id[i]);
+		seq_printf(s, "%-15llu\n",
+			   pci_priv->pm_stats.runtime_put_timestamp_id[i]);
+	}
+
+	return 0;
+}
+
+static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_runtime_pm_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_runtime_pm_debug_write,
+	.open		= cnss_runtime_pm_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int process_drv(struct cnss_plat_data *plat_priv, bool enabled)
+{
+	if (test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_err("DRV cmd must be used before QMI ready\n");
+		return -EINVAL;
+	}
+
+	enabled ? cnss_set_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01) :
+		  cnss_clear_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01);
+
+	cnss_pr_info("%s DRV suspend\n", enabled ? "enable" : "disable");
+	return 0;
+}
+
+static int process_quirks(struct cnss_plat_data *plat_priv, u32 val)
+{
+	enum cnss_debug_quirks i;
+	int ret = 0;
+	unsigned long state;
+	unsigned long quirks = 0;
+
+	for (i = 0, state = val; i < QUIRK_MAX_VALUE; state >>= 1, i++) {
+		switch (i) {
+		case DISABLE_DRV:
+			ret = process_drv(plat_priv, !(state & 0x1));
+			if (!ret)
+				quirks |= (state & 0x1) << i;
+			continue;
+		default:
+			quirks |= (state & 0x1) << i;
+			continue;
+		}
+	}
+
+	plat_priv->ctrl_params.quirks = quirks;
+	return 0;
+}
+
+static ssize_t cnss_control_params_debug_write(struct file *fp,
+					       const char __user *user_buf,
+					       size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *sptr, *token;
+	char *cmd;
+	u32 val;
+	unsigned int len = 0;
+	const char *delim = " ";
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+	if (!sptr)
+		return -EINVAL;
+	cmd = token;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+	if (kstrtou32(token, 0, &val))
+		return -EINVAL;
+
+	if (strcmp(cmd, "quirks") == 0)
+		process_quirks(plat_priv, val);
+	else if (strcmp(cmd, "mhi_timeout") == 0)
+		plat_priv->ctrl_params.mhi_timeout = val;
+	else if (strcmp(cmd, "mhi_m2_timeout") == 0)
+		plat_priv->ctrl_params.mhi_m2_timeout = val;
+	else if (strcmp(cmd, "qmi_timeout") == 0)
+		plat_priv->ctrl_params.qmi_timeout = val;
+	else if (strcmp(cmd, "bdf_type") == 0)
+		plat_priv->ctrl_params.bdf_type = val;
+	else if (strcmp(cmd, "time_sync_period") == 0)
+		plat_priv->ctrl_params.time_sync_period = val;
+	else if (strcmp(cmd, "kern_log_level") == 0) {
+		if (val < MAX_LOG)
+			cnss_kernel_log_level = val;
+	} else if (strcmp(cmd, "ipc_log_level") == 0) {
+		return cnss_set_ipc_log_level(val) ? -EINVAL : count;
+	} else
+		return -EINVAL;
+
+	return count;
+}
+
+static int cnss_show_quirks_state(struct seq_file *s,
+				  struct cnss_plat_data *plat_priv)
+{
+	enum cnss_debug_quirks i;
+	int skip = 0;
+	unsigned long state;
+
+	seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
+	for (i = 0, state = plat_priv->ctrl_params.quirks;
+	     state != 0; state >>= 1, i++) {
+		if (!(state & 0x1))
+			continue;
+		if (skip++)
+			seq_puts(s, " | ");
+
+		switch (i) {
+		case LINK_DOWN_SELF_RECOVERY:
+			seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
+			continue;
+		case SKIP_DEVICE_BOOT:
+			seq_puts(s, "SKIP_DEVICE_BOOT");
+			continue;
+		case USE_CORE_ONLY_FW:
+			seq_puts(s, "USE_CORE_ONLY_FW");
+			continue;
+		case SKIP_RECOVERY:
+			seq_puts(s, "SKIP_RECOVERY");
+			continue;
+		case QMI_BYPASS:
+			seq_puts(s, "QMI_BYPASS");
+			continue;
+		case ENABLE_WALTEST:
+			seq_puts(s, "WALTEST");
+			continue;
+		case ENABLE_PCI_LINK_DOWN_PANIC:
+			seq_puts(s, "PCI_LINK_DOWN_PANIC");
+			continue;
+		case FBC_BYPASS:
+			seq_puts(s, "FBC_BYPASS");
+			continue;
+		case ENABLE_DAEMON_SUPPORT:
+			seq_puts(s, "DAEMON_SUPPORT");
+			continue;
+		case DISABLE_DRV:
+			seq_puts(s, "DISABLE_DRV");
+			continue;
+		case DISABLE_IO_COHERENCY:
+			seq_puts(s, "DISABLE_IO_COHERENCY");
+			continue;
+		case IGNORE_PCI_LINK_FAILURE:
+			seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
+			continue;
+		case DISABLE_TIME_SYNC:
+			seq_puts(s, "DISABLE_TIME_SYNC");
+			continue;
+		case FORCE_ONE_MSI:
+			seq_puts(s, "FORCE_ONE_MSI");
+			continue;
+		default:
+			continue;
+		}
+	}
+	seq_puts(s, ")\n");
+	return 0;
+}
+
+static int cnss_control_params_debug_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *cnss_priv = s->private;
+	u32 ipc_log_level;
+
+	seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
+	seq_puts(s, "<params_name> can be one of below:\n");
+	seq_puts(s, "quirks: Debug quirks for driver\n");
+	seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
+	seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
+	seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
+	seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
+
+	seq_puts(s, "\nCurrent value:\n");
+	cnss_show_quirks_state(s, cnss_priv);
+	seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
+	seq_printf(s, "mhi_m2_timeout: %u\n",
+		   cnss_priv->ctrl_params.mhi_m2_timeout);
+	seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
+	seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
+	seq_printf(s, "time_sync_period: %u\n",
+		   cnss_priv->ctrl_params.time_sync_period);
+	seq_printf(s, "kern_log_level: %u\n", cnss_kernel_log_level);
+
+	ipc_log_level = cnss_get_ipc_log_level();
+	if (ipc_log_level != MAX_LOG)
+		seq_printf(s, "ipc_log_level: %u\n", ipc_log_level);
+
+	return 0;
+}
+
+static int cnss_control_params_debug_open(struct inode *inode,
+					  struct file *file)
+{
+	return single_open(file, cnss_control_params_debug_show,
+			   inode->i_private);
+}
+
+static const struct file_operations cnss_control_params_debug_fops = {
+	.read = seq_read,
+	.write = cnss_control_params_debug_write,
+	.open = cnss_control_params_debug_open,
+	.owner = THIS_MODULE,
+	.llseek = seq_lseek,
+};
+
+static ssize_t cnss_dynamic_feature_write(struct file *fp,
+					  const char __user *user_buf,
+					  size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	int ret = 0;
+	u64 val;
+
+	ret = kstrtou64_from_user(user_buf, count, 0, &val);
+	if (ret)
+		return ret;
+
+	plat_priv->dynamic_feature = val;
+	ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *cnss_priv = s->private;
+
+	seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);
+
+	return 0;
+}
+
+static int cnss_dynamic_feature_open(struct inode *inode,
+				     struct file *file)
+{
+	return single_open(file, cnss_dynamic_feature_show,
+			   inode->i_private);
+}
+
+static const struct file_operations cnss_dynamic_feature_fops = {
+	.read = seq_read,
+	.write = cnss_dynamic_feature_write,
+	.open = cnss_dynamic_feature_open,
+	.owner = THIS_MODULE,
+	.llseek = seq_lseek,
+};
+
+static int cnss_smmu_fault_timestamp_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	seq_printf(s, "smmu irq cb entry timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_ENTRY]);
+	seq_printf(s, "smmu irq cb before doorbell ring timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_DOORBELL_RING]);
+	seq_printf(s, "smmu irq cb after doorbell ring timestamp : %llu ns\n",
+		   pci_priv->smmu_fault_timestamp[SMMU_CB_EXIT]);
+
+	return 0;
+}
+
+static int cnss_smmu_fault_timestamp_open(struct inode *inode,
+					  struct file *file)
+{
+	return single_open(file, cnss_smmu_fault_timestamp_show,
+			   inode->i_private);
+}
+
+static const struct file_operations cnss_smmu_fault_timestamp_fops = {
+	.read = seq_read,
+	.release = single_release,
+	.open = cnss_smmu_fault_timestamp_open,
+	.owner = THIS_MODULE,
+	.llseek = seq_lseek,
+};
+
+#ifdef CONFIG_DEBUG_FS
+#ifdef CONFIG_CNSS2_DEBUG
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+	struct dentry *root_dentry = plat_priv->root_dentry;
+
+	debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
+			    &cnss_dev_boot_debug_fops);
+	debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
+			    &cnss_reg_read_debug_fops);
+	debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
+			    &cnss_reg_write_debug_fops);
+	debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
+			    &cnss_runtime_pm_debug_fops);
+	debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
+			    &cnss_control_params_debug_fops);
+	debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
+			    &cnss_dynamic_feature_fops);
+	debugfs_create_file("cnss_smmu_fault_timestamp", 0600, root_dentry,
+			    plat_priv, &cnss_smmu_fault_timestamp_fops);
+
+	return 0;
+}
+#else
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+#endif
+
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct dentry *root_dentry;
+	char name[CNSS_FS_NAME_SIZE];
+
+	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);
+		goto out;
+	}
+
+	plat_priv->root_dentry = root_dentry;
+
+	debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
+			    &cnss_pin_connect_fops);
+	debugfs_create_file("stats", 0644, root_dentry, plat_priv,
+			    &cnss_stats_fops);
+
+	cnss_create_debug_only_node(plat_priv);
+
+out:
+	return ret;
+}
+
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
+{
+	debugfs_remove_recursive(plat_priv->root_dentry);
+}
+#else
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->root_dentry = NULL;
+	return 0;
+}
+
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
+{
+}
+#endif
+
+#if IS_ENABLED(CONFIG_IPC_LOGGING)
+void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
+			      enum log_level kern_log_level,
+			      enum log_level ipc_log_level, char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list va_args;
+
+	va_start(va_args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &va_args;
+
+	if (kern_log_level <= cnss_kernel_log_level) {
+		switch (kern_log_level) {
+		case EMERG_LOG:
+			pr_emerg("cnss: %pV", &vaf);
+			break;
+		case ALERT_LOG:
+			pr_alert("cnss: %pV", &vaf);
+			break;
+		case CRIT_LOG:
+			pr_crit("cnss: %pV", &vaf);
+			break;
+		case ERR_LOG:
+			pr_err("cnss: %pV", &vaf);
+			break;
+		case WARNING_LOG:
+			pr_warn("cnss: %pV", &vaf);
+			break;
+		case NOTICE_LOG:
+			pr_notice("cnss: %pV", &vaf);
+			break;
+		case INFO_LOG:
+			pr_info("cnss: %pV", &vaf);
+			break;
+		case DEBUG_LOG:
+		case DEBUG_HI_LOG:
+			pr_debug("cnss: %pV", &vaf);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (ipc_log_level <= cnss_ipc_log_level)
+		ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
+
+	va_end(va_args);
+}
+
+static int cnss_ipc_logging_init(void)
+{
+	cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
+						      "cnss", 0);
+	if (!cnss_ipc_log_context) {
+		cnss_pr_err("Unable to create IPC log context\n");
+		return -EINVAL;
+	}
+
+	cnss_ipc_log_long_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
+							   "cnss-long", 0);
+	if (!cnss_ipc_log_long_context) {
+		cnss_pr_err("Unable to create IPC long log context\n");
+		ipc_log_context_destroy(cnss_ipc_log_context);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void cnss_ipc_logging_deinit(void)
+{
+	if (cnss_ipc_log_long_context) {
+		ipc_log_context_destroy(cnss_ipc_log_long_context);
+		cnss_ipc_log_long_context = NULL;
+	}
+
+	if (cnss_ipc_log_context) {
+		ipc_log_context_destroy(cnss_ipc_log_context);
+		cnss_ipc_log_context = NULL;
+	}
+}
+#else
+static int cnss_ipc_logging_init(void) { return 0; }
+static void cnss_ipc_logging_deinit(void) {}
+void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
+			      enum log_level kern_log_level,
+			      enum log_level ipc_log_level, char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list va_args;
+
+	va_start(va_args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &va_args;
+
+	if (kern_log_level <= cnss_kernel_log_level) {
+		switch (kern_log_level) {
+		case EMERG_LOG:
+			pr_emerg("cnss: %pV", &vaf);
+			break;
+		case ALERT_LOG:
+			pr_alert("cnss: %pV", &vaf);
+			break;
+		case CRIT_LOG:
+			pr_crit("cnss: %pV", &vaf);
+			break;
+		case ERR_LOG:
+			pr_err("cnss: %pV", &vaf);
+			break;
+		case WARNING_LOG:
+			pr_warn("cnss: %pV", &vaf);
+			break;
+		case NOTICE_LOG:
+			pr_notice("cnss: %pV", &vaf);
+			break;
+		case INFO_LOG:
+			pr_info("cnss: %pV", &vaf);
+			break;
+		case DEBUG_LOG:
+		case DEBUG_HI_LOG:
+			pr_debug("cnss: %pV", &vaf);
+			break;
+		default:
+			break;
+		}
+	}
+
+	va_end(va_args);
+}
+#endif
+
+int cnss_debug_init(void)
+{
+	return cnss_ipc_logging_init();
+}
+
+void cnss_debug_deinit(void)
+{
+	cnss_ipc_logging_deinit();
+}

+ 108 - 0
qcom/opensource/wlan/platform/cnss2/debug.h

@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+#ifndef _CNSS_DEBUG_H
+#define _CNSS_DEBUG_H
+
+#include <linux/printk.h>
+
+enum log_level {
+	EMERG_LOG = 0,
+	ALERT_LOG = 1,
+	CRIT_LOG = 2,
+	ERR_LOG = 3,
+	WARNING_LOG = 4,
+	NOTICE_LOG = 5,
+	INFO_LOG = 6,
+	DEBUG_LOG = 7,
+	DEBUG_HI_LOG = 8,
+	MAX_LOG = 9,
+};
+
+extern enum log_level cnss_kernel_log_level;
+
+#if IS_ENABLED(CONFIG_IPC_LOGGING)
+#include <linux/ipc_logging.h>
+#include <asm/current.h>
+
+extern void *cnss_ipc_log_context;
+extern void *cnss_ipc_log_long_context;
+extern enum log_level cnss_ipc_log_level;
+
+#ifdef CONFIG_CNSS2_DEBUG
+#define CNSS_IPC_LOG_PAGES              100
+#else
+#define CNSS_IPC_LOG_PAGES              50
+#endif
+#define cnss_debug_log_print(_x...) \
+		 cnss_debug_ipc_log_print(cnss_ipc_log_context, _x)
+
+#define cnss_debug_log_long_print(_x...) \
+		 cnss_debug_ipc_log_print(cnss_ipc_log_long_context, _x)
+#else
+#define cnss_debug_log_print(_x...) \
+		 cnss_debug_ipc_log_print((void *)NULL, _x)
+#define cnss_debug_log_long_print(_x...) \
+		 cnss_debug_ipc_log_print((void *)NULL, _x)
+#endif
+
+#define proc_name (in_irq() ? "irq" : \
+		   (in_softirq() ? "soft_irq" : current->comm))
+
+#define cnss_pr_err(_fmt, ...) \
+	cnss_debug_log_print(proc_name, __func__, \
+			     ERR_LOG, ERR_LOG, _fmt, ##__VA_ARGS__)
+
+#define cnss_pr_warn(_fmt, ...) \
+	cnss_debug_log_print(proc_name, __func__, \
+			     WARNING_LOG, WARNING_LOG, _fmt, ##__VA_ARGS__)
+
+#define cnss_pr_info(_fmt, ...) \
+	cnss_debug_log_print(proc_name, __func__, \
+			     INFO_LOG, INFO_LOG, _fmt, ##__VA_ARGS__)
+
+#define cnss_pr_dbg(_fmt, ...) \
+	cnss_debug_log_print(proc_name, __func__, \
+			     DEBUG_LOG, DEBUG_LOG, _fmt, ##__VA_ARGS__)
+
+#define cnss_pr_vdbg(_fmt, ...) \
+	cnss_debug_log_long_print(proc_name, __func__, \
+				  DEBUG_LOG, DEBUG_LOG, _fmt, ##__VA_ARGS__)
+
+#define cnss_pr_buf(_fmt, ...) \
+	cnss_debug_log_long_print(proc_name, __func__, \
+				  DEBUG_HI_LOG, DEBUG_LOG, _fmt, ##__VA_ARGS__)
+#define cnss_pr_dbg_buf(_fmt, ...) \
+	cnss_debug_log_long_print(proc_name, __func__, \
+				  DEBUG_HI_LOG, DEBUG_HI_LOG, _fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_CNSS2_DEBUG
+#define CNSS_ASSERT(_condition) do {					\
+		if (!(_condition)) {					\
+			cnss_pr_err("ASSERT at line %d\n",		\
+				    __LINE__);				\
+			BUG();						\
+		}							\
+	} while (0)
+#else
+#define CNSS_ASSERT(_condition) do {					\
+		if (!(_condition)) {					\
+			cnss_pr_err("ASSERT at line %d\n",		\
+				    __LINE__);				\
+			WARN_ON(1);					\
+		}							\
+	} while (0)
+#endif
+
+#define cnss_fatal_err(_fmt, ...)					\
+	cnss_pr_err("fatal: " _fmt, ##__VA_ARGS__)
+
+int cnss_debug_init(void);
+void cnss_debug_deinit(void);
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv);
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv);
+void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
+			      enum log_level kern_log_level,
+			      enum log_level ipc_log_level, char *fmt, ...);
+#endif /* _CNSS_DEBUG_H */

+ 217 - 0
qcom/opensource/wlan/platform/cnss2/genl.c

@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "cnss_genl: " fmt
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include "main.h"
+#include "debug.h"
+#include "genl.h"
+
+#define CNSS_GENL_FAMILY_NAME "cnss-genl"
+#define CNSS_GENL_MCAST_GROUP_NAME "cnss-genl-grp"
+#define CNSS_GENL_VERSION 1
+#define CNSS_GENL_DATA_LEN_MAX (15 * 1024)
+#define CNSS_GENL_STR_LEN_MAX 16
+
+enum {
+	CNSS_GENL_ATTR_MSG_UNSPEC,
+	CNSS_GENL_ATTR_MSG_TYPE,
+	CNSS_GENL_ATTR_MSG_FILE_NAME,
+	CNSS_GENL_ATTR_MSG_TOTAL_SIZE,
+	CNSS_GENL_ATTR_MSG_SEG_ID,
+	CNSS_GENL_ATTR_MSG_END,
+	CNSS_GENL_ATTR_MSG_DATA_LEN,
+	CNSS_GENL_ATTR_MSG_DATA,
+	__CNSS_GENL_ATTR_MAX,
+};
+
+#define CNSS_GENL_ATTR_MAX (__CNSS_GENL_ATTR_MAX - 1)
+
+enum {
+	CNSS_GENL_CMD_UNSPEC,
+	CNSS_GENL_CMD_MSG,
+	__CNSS_GENL_CMD_MAX,
+};
+
+#define CNSS_GENL_CMD_MAX (__CNSS_GENL_CMD_MAX - 1)
+
+static struct nla_policy cnss_genl_msg_policy[CNSS_GENL_ATTR_MAX + 1] = {
+	[CNSS_GENL_ATTR_MSG_TYPE] = { .type = NLA_U8 },
+	[CNSS_GENL_ATTR_MSG_FILE_NAME] = { .type = NLA_NUL_STRING,
+					   .len = CNSS_GENL_STR_LEN_MAX },
+	[CNSS_GENL_ATTR_MSG_TOTAL_SIZE] = { .type = NLA_U32 },
+	[CNSS_GENL_ATTR_MSG_SEG_ID] = { .type = NLA_U32 },
+	[CNSS_GENL_ATTR_MSG_END] = { .type = NLA_U8 },
+	[CNSS_GENL_ATTR_MSG_DATA_LEN] = { .type = NLA_U32 },
+	[CNSS_GENL_ATTR_MSG_DATA] = { .type = NLA_BINARY,
+				      .len = CNSS_GENL_DATA_LEN_MAX },
+};
+
+static int cnss_genl_process_msg(struct sk_buff *skb, struct genl_info *info)
+{
+	return 0;
+}
+
+static struct genl_ops cnss_genl_ops[] = {
+	{
+		.cmd = CNSS_GENL_CMD_MSG,
+		.doit = cnss_genl_process_msg,
+	},
+};
+
+static struct genl_multicast_group cnss_genl_mcast_grp[] = {
+	{
+		.name = CNSS_GENL_MCAST_GROUP_NAME,
+	},
+};
+
+static struct genl_family cnss_genl_family = {
+	.id = 0,
+	.hdrsize = 0,
+	.name = CNSS_GENL_FAMILY_NAME,
+	.version = CNSS_GENL_VERSION,
+	.maxattr = CNSS_GENL_ATTR_MAX,
+	.policy = cnss_genl_msg_policy,
+	.module = THIS_MODULE,
+	.ops = cnss_genl_ops,
+	.n_ops = ARRAY_SIZE(cnss_genl_ops),
+	.mcgrps = cnss_genl_mcast_grp,
+	.n_mcgrps = ARRAY_SIZE(cnss_genl_mcast_grp),
+};
+
+static int cnss_genl_send_data(u8 type, char *file_name, u32 total_size,
+			       u32 seg_id, u8 end, u32 data_len, u8 *msg_buff)
+{
+	struct sk_buff *skb = NULL;
+	void *msg_header = NULL;
+	int ret = 0;
+	char filename[CNSS_GENL_STR_LEN_MAX + 1];
+
+	cnss_pr_dbg_buf("type: %u, file_name %s, total_size: %x, seg_id %u, end %u, data_len %u\n",
+			type, file_name, total_size, seg_id, end, data_len);
+
+	if (!file_name)
+		strlcpy(filename, "default", sizeof(filename));
+	else
+		strlcpy(filename, file_name, sizeof(filename));
+
+	skb = genlmsg_new(NLMSG_HDRLEN +
+			  nla_total_size(sizeof(type)) +
+			  nla_total_size(strlen(filename) + 1) +
+			  nla_total_size(sizeof(total_size)) +
+			  nla_total_size(sizeof(seg_id)) +
+			  nla_total_size(sizeof(end)) +
+			  nla_total_size(sizeof(data_len)) +
+			  nla_total_size(data_len), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	msg_header = genlmsg_put(skb, 0, 0,
+				 &cnss_genl_family, 0,
+				 CNSS_GENL_CMD_MSG);
+	if (!msg_header) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	ret = nla_put_u8(skb, CNSS_GENL_ATTR_MSG_TYPE, type);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put_string(skb, CNSS_GENL_ATTR_MSG_FILE_NAME, filename);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_TOTAL_SIZE, total_size);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_SEG_ID, seg_id);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put_u8(skb, CNSS_GENL_ATTR_MSG_END, end);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put_u32(skb, CNSS_GENL_ATTR_MSG_DATA_LEN, data_len);
+	if (ret < 0)
+		goto fail;
+	ret = nla_put(skb, CNSS_GENL_ATTR_MSG_DATA, data_len, msg_buff);
+	if (ret < 0)
+		goto fail;
+
+	genlmsg_end(skb, msg_header);
+	ret = genlmsg_multicast(&cnss_genl_family, skb, 0, 0, GFP_KERNEL);
+	if (ret < 0)
+		cnss_pr_err("Fail to send genl msg: %d\n", ret);
+
+	return ret;
+fail:
+	cnss_pr_err("Fail to generate genl msg: %d\n", ret);
+	if (skb)
+		nlmsg_free(skb);
+	return ret;
+}
+
+int cnss_genl_send_msg(void *buff, u8 type, char *file_name, u32 total_size)
+{
+	int ret = 0;
+	u8 *msg_buff = buff;
+	u32 remaining = total_size;
+	u32 seg_id = 0;
+	u32 data_len = 0;
+	u8 end = 0;
+	u8 retry;
+
+	cnss_pr_dbg_buf("type: %u, total_size: %x\n", type, total_size);
+
+	while (remaining) {
+		if (remaining > CNSS_GENL_DATA_LEN_MAX) {
+			data_len = CNSS_GENL_DATA_LEN_MAX;
+		} else {
+			data_len = remaining;
+			end = 1;
+		}
+
+		for (retry = 0; retry < 2; retry++) {
+			ret = cnss_genl_send_data(type, file_name, total_size,
+						  seg_id, end, data_len,
+						  msg_buff);
+			if (ret >= 0)
+				break;
+			msleep(100);
+		}
+
+		if (ret < 0) {
+			cnss_pr_err("fail to send genl data, ret %d\n", ret);
+			return ret;
+		}
+
+		remaining -= data_len;
+		msg_buff += data_len;
+		seg_id++;
+	}
+
+	return ret;
+}
+
+int cnss_genl_init(void)
+{
+	int ret = 0;
+
+	ret = genl_register_family(&cnss_genl_family);
+	if (ret != 0)
+		cnss_pr_err("genl_register_family fail: %d\n", ret);
+
+	return ret;
+}
+
+void cnss_genl_exit(void)
+{
+	genl_unregister_family(&cnss_genl_family);
+}

+ 17 - 0
qcom/opensource/wlan/platform/cnss2/genl.h

@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */
+
+#ifndef __CNSS_GENL_H__
+#define __CNSS_GENL_H__
+
+enum cnss_genl_msg_type {
+	CNSS_GENL_MSG_TYPE_UNSPEC,
+	CNSS_GENL_MSG_TYPE_QDSS,
+};
+
+int cnss_genl_init(void);
+void cnss_genl_exit(void);
+int cnss_genl_send_msg(void *buff, u8 type,
+		       char *file_name, u32 total_size);
+
+#endif

+ 5800 - 0
qcom/opensource/wlan/platform/cnss2/main.c

@@ -0,0 +1,5800 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/delay.h>
+#include <linux/devcoredump.h>
+#include <linux/elf.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_wakeup.h>
+#include <linux/reboot.h>
+#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>
+#endif
+#if IS_ENABLED(CONFIG_QCOM_MINIDUMP)
+#include <soc/qcom/minidump.h>
+#endif
+
+#include "cnss_plat_ipc_qmi.h"
+#include "cnss_utils.h"
+#include "main.h"
+#include "bus.h"
+#include "debug.h"
+#include "genl.h"
+#include "reg.h"
+
+#ifdef CONFIG_CNSS_HW_SECURE_DISABLE
+#ifdef CONFIG_CNSS_HW_SECURE_SMEM
+#include <linux/soc/qcom/smem.h>
+#define PERISEC_SMEM_ID 651
+#define HW_WIFI_UID 0x508
+#else
+#include "smcinvoke.h"
+#include "smcinvoke_object.h"
+#include "IClientEnv.h"
+#define HW_STATE_UID 0x108
+#define HW_OP_GET_STATE 1
+#define HW_WIFI_UID 0x508
+#define FEATURE_NOT_SUPPORTED 12
+#define PERIPHERAL_NOT_FOUND 10
+#endif
+#endif
+
+#define CNSS_DUMP_FORMAT_VER		0x11
+#define CNSS_DUMP_FORMAT_VER_V2		0x22
+#define CNSS_DUMP_MAGIC_VER_V2		0x42445953
+#define CNSS_DUMP_NAME			"CNSS_WLAN"
+#define CNSS_DUMP_DESC_SIZE		0x1000
+#define CNSS_DUMP_SEG_VER		0x1
+#define FILE_SYSTEM_READY		1
+#define FW_READY_TIMEOUT		20000
+#define FW_ASSERT_TIMEOUT		5000
+#define CNSS_EVENT_PENDING		2989
+#define POWER_RESET_MIN_DELAY_MS	100
+#define MAX_NAME_LEN			12
+
+#define CNSS_QUIRKS_DEFAULT		0
+#ifdef CONFIG_CNSS_EMULATION
+#define CNSS_MHI_TIMEOUT_DEFAULT	90000
+#define CNSS_MHI_M2_TIMEOUT_DEFAULT	2000
+#define CNSS_QMI_TIMEOUT_DEFAULT	90000
+#else
+#define CNSS_MHI_TIMEOUT_DEFAULT	0
+#define CNSS_MHI_M2_TIMEOUT_DEFAULT	25
+#define CNSS_QMI_TIMEOUT_DEFAULT	10000
+#endif
+#define CNSS_BDF_TYPE_DEFAULT		CNSS_BDF_ELF
+#define CNSS_TIME_SYNC_PERIOD_DEFAULT	900000
+#define CNSS_MIN_TIME_SYNC_PERIOD	2000
+#define CNSS_DMS_QMI_CONNECTION_WAIT_MS 50
+#define CNSS_DMS_QMI_CONNECTION_WAIT_RETRY 200
+#define CNSS_DAEMON_CONNECT_TIMEOUT_MS  30000
+#define CNSS_CAL_DB_FILE_NAME "wlfw_cal_db.bin"
+#define CNSS_CAL_START_PROBE_WAIT_RETRY_MAX 100
+#define CNSS_CAL_START_PROBE_WAIT_MS	500
+#define CNSS_TIME_SYNC_PERIOD_INVALID	0xFFFFFFFF
+
+enum cnss_cal_db_op {
+	CNSS_CAL_DB_UPLOAD,
+	CNSS_CAL_DB_DOWNLOAD,
+	CNSS_CAL_DB_INVALID_OP,
+};
+
+enum cnss_recovery_type {
+	CNSS_WLAN_RECOVERY = 0x1,
+	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 atomic_t plat_env_count;
+#else
+static struct cnss_plat_data *plat_env;
+#endif
+
+static bool cnss_allow_driver_loading;
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+	"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+	"utfbd30.bin", "epping30.bin", "evicted30.bin"
+};
+
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+	"qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+	"utfbd.bin", "epping.bin", "evicted.bin"
+};
+
+struct cnss_driver_event {
+	struct list_head list;
+	enum cnss_driver_event_type type;
+	bool sync;
+	struct completion complete;
+	int ret;
+	void *data;
+};
+
+bool cnss_check_driver_loading_allowed(void)
+{
+	return cnss_allow_driver_loading;
+}
+
+#ifdef CONFIG_CNSS_SUPPORT_DUAL_DEV
+static void cnss_init_plat_env_count(void)
+{
+	atomic_set(&plat_env_count, 0);
+}
+
+static void cnss_inc_plat_env_count(void)
+{
+	atomic_inc(&plat_env_count);
+}
+
+static void cnss_dec_plat_env_count(void)
+{
+	atomic_dec(&plat_env_count);
+}
+
+static int cnss_get_plat_env_count(void)
+{
+	return atomic_read(&plat_env_count);
+}
+
+int cnss_get_max_plat_env_count(void)
+{
+	return CNSS_MAX_DEV_NUM;
+}
+
+static void cnss_set_plat_priv(struct platform_device *plat_dev,
+			       struct cnss_plat_data *plat_priv)
+{
+	int env_count = cnss_get_plat_env_count();
+
+	cnss_pr_dbg("Set plat_priv at %d", env_count);
+	if (plat_priv) {
+		plat_priv->plat_idx = env_count;
+		plat_env[plat_priv->plat_idx] = plat_priv;
+		cnss_inc_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 < CNSS_MAX_DEV_NUM; i++) {
+		if (plat_env[i] && plat_env[i]->plat_dev == plat_dev)
+			return plat_env[i];
+	}
+	return NULL;
+}
+
+struct cnss_plat_data *cnss_get_first_plat_priv(struct platform_device
+						 *plat_dev)
+{
+	int i;
+
+	if (!plat_dev) {
+		for (i = 0; i < CNSS_MAX_DEV_NUM; i++) {
+			if (plat_env[i])
+				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;
+	cnss_dec_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;
+	int env_count = cnss_get_plat_env_count();
+
+	if (env_count >= CNSS_MAX_DEV_NUM) {
+		cnss_pr_err("ERROR: No space to store plat_priv\n");
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+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 < CNSS_MAX_DEV_NUM; i++) {
+		if (plat_env[i] && 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_init_plat_env_count(void)
+{
+}
+
+static void cnss_set_plat_priv(struct platform_device *plat_dev,
+			       struct cnss_plat_data *plat_priv)
+{
+	plat_env = plat_priv;
+}
+
+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
+
+void cnss_get_sleep_clk_supported(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->sleep_clk = of_property_read_bool(plat_priv->dev_node,
+						     "qcom,sleep-clk-support");
+	cnss_pr_dbg("qcom,sleep-clk-support is %d\n",
+		    plat_priv->sleep_clk);
+}
+
+void cnss_get_bwscal_info(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->no_bwscale = of_property_read_bool(plat_priv->dev_node,
+						      "qcom,no-bwscale");
+}
+
+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
+ * @seg: segment count
+ *
+ * Return: 0 on success, negative value on failure
+ */
+int cnss_get_mem_seg_count(enum cnss_remote_mem_type type, u32 *seg)
+{
+	struct cnss_plat_data *plat_priv;
+
+	plat_priv = cnss_get_plat_priv(NULL);
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (type) {
+	case CNSS_REMOTE_MEM_TYPE_FW:
+		*seg = plat_priv->fw_mem_seg_len;
+		break;
+	case CNSS_REMOTE_MEM_TYPE_QDSS:
+		*seg = plat_priv->qdss_mem_seg_len;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_mem_seg_count);
+
+/**
+ * cnss_get_wifi_kobject -return wifi kobject
+ * Return: Null, to maintain driver comnpatibilty
+ */
+struct kobject *cnss_get_wifi_kobj(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv;
+
+	plat_priv = cnss_get_plat_priv(NULL);
+	if (!plat_priv)
+		return NULL;
+
+	return plat_priv->wifi_kobj;
+}
+EXPORT_SYMBOL(cnss_get_wifi_kobj);
+
+/**
+ * cnss_get_mem_segment_info - Get memory info of different type
+ * @type: memory type
+ * @segment: array to save the segment info
+ * @seg: segment count
+ *
+ * Return: 0 on success, negative value on failure
+ */
+int cnss_get_mem_segment_info(enum cnss_remote_mem_type type,
+			      struct cnss_mem_segment segment[],
+			      u32 segment_count)
+{
+	struct cnss_plat_data *plat_priv;
+	u32 i;
+
+	plat_priv = cnss_get_plat_priv(NULL);
+	if (!plat_priv)
+		return -ENODEV;
+
+	switch (type) {
+	case CNSS_REMOTE_MEM_TYPE_FW:
+		if (segment_count > plat_priv->fw_mem_seg_len)
+			segment_count = plat_priv->fw_mem_seg_len;
+		for (i = 0; i < segment_count; i++) {
+			segment[i].size = plat_priv->fw_mem[i].size;
+			segment[i].va = plat_priv->fw_mem[i].va;
+			segment[i].pa = plat_priv->fw_mem[i].pa;
+		}
+		break;
+	case CNSS_REMOTE_MEM_TYPE_QDSS:
+		if (segment_count > plat_priv->qdss_mem_seg_len)
+			segment_count = plat_priv->qdss_mem_seg_len;
+		for (i = 0; i < segment_count; i++) {
+			segment[i].size = plat_priv->qdss_mem[i].size;
+			segment[i].va = plat_priv->qdss_mem[i].va;
+			segment[i].pa = plat_priv->qdss_mem[i].pa;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+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;
+}
+
+bool cnss_get_audio_shared_iommu_group_cap(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct device_node *audio_ion_node;
+	struct device_node *cnss_iommu_group_node;
+	struct device_node *audio_iommu_group_node;
+
+	if (!plat_priv)
+		return false;
+
+	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 false;
+	}
+
+	audio_iommu_group_node = of_parse_phandle(audio_ion_node,
+						  "qcom,iommu-group", 0);
+	of_node_put(audio_ion_node);
+	if (!audio_iommu_group_node) {
+		cnss_pr_err("Unable to get audio iommu group phandle");
+		return false;
+	}
+	of_node_put(audio_iommu_group_node);
+
+	cnss_iommu_group_node = of_parse_phandle(dev->of_node,
+						 "qcom,iommu-group", 0);
+	if (!cnss_iommu_group_node) {
+		cnss_pr_err("Unable to get cnss iommu group phandle");
+		return false;
+	}
+	of_node_put(cnss_iommu_group_node);
+
+	if (cnss_iommu_group_node == audio_iommu_group_node) {
+		plat_priv->is_audio_shared_iommu_group = true;
+		cnss_pr_info("CNSS and Audio share IOMMU group");
+	} else {
+		cnss_pr_info("CNSS and Audio do not share IOMMU group");
+	}
+
+	return plat_priv->is_audio_shared_iommu_group;
+}
+EXPORT_SYMBOL(cnss_get_audio_shared_iommu_group_cap);
+
+int cnss_set_feature_list(struct cnss_plat_data *plat_priv,
+			  enum cnss_feature_v01 feature)
+{
+	if (unlikely(!plat_priv || feature >= CNSS_MAX_FEATURE_V01))
+		return -EINVAL;
+
+	plat_priv->feature_list |= 1 << feature;
+	return 0;
+}
+
+int cnss_clear_feature_list(struct cnss_plat_data *plat_priv,
+			    enum cnss_feature_v01 feature)
+{
+	if (unlikely(!plat_priv || feature >= CNSS_MAX_FEATURE_V01))
+		return -EINVAL;
+
+	plat_priv->feature_list &= ~(1 << feature);
+	return 0;
+}
+
+int cnss_get_feature_list(struct cnss_plat_data *plat_priv,
+			  u64 *feature_list)
+{
+	if (unlikely(!plat_priv))
+		return -EINVAL;
+
+	*feature_list = plat_priv->feature_list;
+	return 0;
+}
+
+size_t cnss_get_platform_name(struct cnss_plat_data *plat_priv,
+			      char *buf, const size_t buf_len)
+{
+	if (unlikely(!plat_priv || !buf || !buf_len))
+		return 0;
+
+	if (of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				  "platform-name-required")) {
+		struct device_node *root;
+
+		root = of_find_node_by_path("/");
+		if (root) {
+			const char *model;
+			size_t model_len;
+
+			model = of_get_property(root, "model", NULL);
+			if (model) {
+				model_len = strlcpy(buf, model, buf_len);
+				cnss_pr_dbg("Platform name: %s (%zu)\n",
+					    buf, model_len);
+
+				return model_len;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv)
+{
+	if (atomic_inc_return(&plat_priv->pm_count) != 1)
+		return;
+
+	cnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n",
+		    plat_priv->driver_state,
+		    atomic_read(&plat_priv->pm_count));
+	pm_stay_awake(&plat_priv->plat_dev->dev);
+}
+
+void cnss_pm_relax(struct cnss_plat_data *plat_priv)
+{
+	int r = atomic_dec_return(&plat_priv->pm_count);
+
+	WARN_ON(r < 0);
+
+	if (r != 0)
+		return;
+
+	cnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n",
+		    plat_priv->driver_state,
+		    atomic_read(&plat_priv->pm_count));
+	pm_relax(&plat_priv->plat_dev->dev);
+}
+
+int cnss_get_fw_files_for_target(struct device *dev,
+				 struct cnss_fw_files *pfw_files,
+				 u32 target_type, u32 target_version)
+{
+	if (!pfw_files)
+		return -ENODEV;
+
+	switch (target_version) {
+	case QCA6174_REV3_VERSION:
+	case QCA6174_REV3_2_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+		break;
+	default:
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+		cnss_pr_err("Unknown target version, type: 0x%X, version: 0x%X",
+			    target_type, target_version);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!cap)
+		return -EINVAL;
+
+	*cap = plat_priv->cap;
+	cnss_pr_dbg("Platform cap_flag is 0x%x\n", cap->cap_flag);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+/**
+ * cnss_get_fw_cap - Check whether FW supports specific capability or not
+ * @dev: Device
+ * @fw_cap: FW Capability which needs to be checked
+ *
+ * Return: TRUE if supported, FALSE on failure or if not supported
+ */
+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 is_supported = false;
+
+	if (!plat_priv)
+		return is_supported;
+
+	if (!plat_priv->fw_caps)
+		return is_supported;
+
+	switch (fw_cap) {
+	case CNSS_FW_CAP_DIRECT_LINK_SUPPORT:
+		is_supported = !!(plat_priv->fw_caps &
+				  QMI_WLFW_DIRECT_LINK_SUPPORT_V01);
+		break;
+	case CNSS_FW_CAP_CALDB_SEG_DDR_SUPPORT:
+		is_supported = !!(plat_priv->fw_caps &
+				  QMI_WLFW_CALDB_SEG_DDR_SUPPORT_V01);
+		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,
+		    is_supported ? "supported" : "not supported");
+	return is_supported;
+}
+EXPORT_SYMBOL(cnss_get_fw_cap);
+
+/**
+ * cnss_audio_is_direct_link_supported - Check whether Audio can be used for direct link support
+ * @dev: Device
+ *
+ * Return: TRUE if supported, FALSE on failure or if not supported
+ */
+bool cnss_audio_is_direct_link_supported(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	bool is_supported = false;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv not available to check audio direct link cap\n");
+		return is_supported;
+	}
+
+	if (cnss_get_audio_iommu_domain(plat_priv) == 0)
+		is_supported = true;
+
+	return is_supported;
+}
+EXPORT_SYMBOL(cnss_audio_is_direct_link_supported);
+
+/**
+ * cnss_ipa_wlan_shared_smmu_supported: Check whether shared SMMU context bank
+ *                                      can be used between IPA and WLAN.
+ * @dev: Device
+ *
+ * Return: TRUE if supported, FALSE on failure or if not supported
+ */
+bool cnss_ipa_wlan_shared_smmu_supported(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct device_node *ipa_wlan_smmu_node;
+	struct device_node *cnss_iommu_group_node;
+	struct device_node *ipa_iommu_group_node;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv not available for IPA Shared CB cap\n");
+		return false;
+	}
+
+	ipa_wlan_smmu_node = of_find_compatible_node(NULL, NULL,
+						     "qcom,ipa-smmu-wlan-cb");
+	if (!ipa_wlan_smmu_node) {
+		cnss_pr_err("ipa-smmu-wlan-cb not enabled");
+		return false;
+	}
+
+	ipa_iommu_group_node = of_parse_phandle(ipa_wlan_smmu_node,
+						"qcom,iommu-group", 0);
+	of_node_put(ipa_wlan_smmu_node);
+
+	if (!ipa_iommu_group_node) {
+		cnss_pr_err("Unable to get ipa iommu group phandle");
+		return false;
+	}
+	of_node_put(ipa_iommu_group_node);
+
+	cnss_iommu_group_node = of_parse_phandle(dev->of_node,
+						 "qcom,iommu-group", 0);
+	if (!cnss_iommu_group_node) {
+		cnss_pr_err("Unable to get cnss iommu group phandle");
+		return false;
+	}
+	of_node_put(cnss_iommu_group_node);
+
+	if (cnss_iommu_group_node == ipa_iommu_group_node) {
+		plat_priv->ipa_shared_cb_enable = true;
+		cnss_pr_info("CNSS and IPA share IOMMU group");
+	} else {
+		cnss_pr_info("CNSS and IPA do not share IOMMU group");
+	}
+
+	return plat_priv->ipa_shared_cb_enable;
+}
+EXPORT_SYMBOL(cnss_ipa_wlan_shared_smmu_supported);
+
+void cnss_request_pm_qos(struct device *dev, u32 qos_val)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return;
+
+	cpu_latency_qos_add_request(&plat_priv->qos_request, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return;
+
+	cpu_latency_qos_remove_request(&plat_priv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+int cnss_wlan_enable(struct device *dev,
+		     struct cnss_wlan_enable_cfg *config,
+		     enum cnss_driver_mode mode,
+		     const char *host_version)
+{
+	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;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks))
+		return 0;
+
+	if (!config || !host_version) {
+		cnss_pr_err("Invalid config or host_version pointer\n");
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
+		    mode, config, host_version);
+
+	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;
+
+skip_cfg:
+	ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, mode);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_enable);
+
+int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
+{
+	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;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks))
+		return 0;
+
+	ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
+	cnss_bus_free_qdss_mem(plat_priv);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_disable);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
+int cnss_iommu_map(struct iommu_domain *domain,
+		   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
+{
+	return iommu_map(domain, iova, paddr, size, prot);
+}
+#else
+int cnss_iommu_map(struct iommu_domain *domain,
+		   unsigned long iova, phys_addr_t paddr, size_t size, int prot)
+{
+	return iommu_map(domain, iova, paddr, size, prot, GFP_KERNEL);
+}
+#endif
+
+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;
+
+	if (plat_priv->is_audio_shared_iommu_group)
+		return 0;
+
+	page_offset = iova & (PAGE_SIZE - 1);
+	if (page_offset + size > PAGE_SIZE)
+		size += PAGE_SIZE;
+
+	iova -= page_offset;
+	paddr -= page_offset;
+
+	return cnss_iommu_map(plat_priv->audio_iommu_domain, iova, paddr,
+			      roundup(size, PAGE_SIZE), IOMMU_READ |
+			      IOMMU_WRITE | IOMMU_CACHE);
+}
+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 || !plat_priv->audio_iommu_domain ||
+	    plat_priv->is_audio_shared_iommu_group)
+		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_get_fw_lpass_shared_mem(struct device *dev, dma_addr_t *iova,
+				 size_t *size)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	uint8_t i;
+
+	if (!plat_priv)
+		return -EINVAL;
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (plat_priv->fw_mem[i].type ==
+		    QMI_WLFW_MEM_LPASS_SHARED_V01) {
+			*iova = plat_priv->fw_mem[i].pa;
+			*size = plat_priv->fw_mem[i].size;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_get_fw_lpass_shared_mem);
+
+int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
+		      u32 data_len, u8 *output)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Invalid state for athdiag read: 0x%lx\n",
+			    plat_priv->driver_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, offset, mem_type,
+					       data_len, output);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_read);
+
+int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
+		       u32 data_len, u8 *input)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Invalid state for athdiag write: 0x%lx\n",
+			    plat_priv->driver_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, offset, mem_type,
+						data_len, input);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_write);
+
+int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
+{
+	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;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	return cnss_wlfw_ini_send_sync(plat_priv, fw_log_mode);
+}
+EXPORT_SYMBOL(cnss_set_fw_log_mode);
+
+int cnss_set_pcie_gen_speed(struct device *dev, u8 pcie_gen_speed)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -EINVAL;
+
+	if (!plat_priv->fw_pcie_gen_switch) {
+		cnss_pr_err("Firmware does not support PCIe gen switch\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (pcie_gen_speed < QMI_PCIE_GEN_SPEED_1_V01 ||
+	    pcie_gen_speed > QMI_PCIE_GEN_SPEED_3_V01)
+		return -EINVAL;
+
+	cnss_pr_dbg("WLAN provided PCIE gen speed: %d\n", pcie_gen_speed);
+	plat_priv->pcie_gen_speed = pcie_gen_speed;
+	return 0;
+}
+EXPORT_SYMBOL(cnss_set_pcie_gen_speed);
+
+static bool cnss_is_aux_support_enabled(struct cnss_plat_data *plat_priv)
+{
+	switch (plat_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		if (!plat_priv->fw_aux_uc_support) {
+			cnss_pr_dbg("FW does not support aux uc capability\n");
+			return false;
+		}
+		break;
+	default:
+		cnss_pr_dbg("Host does not support aux uc capability\n");
+		return false;
+	}
+
+	return true;
+}
+
+static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	set_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+
+	ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	cnss_bus_load_tme_patch(plat_priv);
+
+	cnss_wlfw_tme_patch_dnld_send_sync(plat_priv,
+					   WLFW_TME_LITE_PATCH_FILE_V01);
+
+	if (plat_priv->hds_enabled)
+		cnss_wlfw_bdf_dnld_send_sync(plat_priv, CNSS_BDF_HDS);
+
+	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;
+
+	ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv,
+					   plat_priv->ctrl_params.bdf_type);
+	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;
+
+	ret = cnss_wlfw_m3_dnld_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	if (cnss_is_aux_support_enabled(plat_priv)) {
+		ret = cnss_bus_load_aux(plat_priv);
+		if (ret)
+			goto out;
+
+		ret = cnss_wlfw_aux_dnld_send_sync(plat_priv);
+		if (ret)
+			goto out;
+	}
+
+	cnss_wlfw_qdss_dnld_send_sync(plat_priv);
+
+	return 0;
+out:
+	return ret;
+}
+
+static int cnss_request_antenna_sharing(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	if (!plat_priv->antenna) {
+		ret = cnss_wlfw_antenna_switch_send_sync(plat_priv);
+		if (ret)
+			goto out;
+	}
+
+	if (test_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state)) {
+		ret = coex_antenna_switch_to_wlan_send_sync_msg(plat_priv);
+		if (ret)
+			goto out;
+	}
+
+	ret = cnss_wlfw_antenna_grant_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static void cnss_release_antenna_sharing(struct cnss_plat_data *plat_priv)
+{
+	if (test_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state))
+		coex_antenna_switch_to_mdm_send_sync_msg(plat_priv);
+}
+
+static int cnss_setup_dms_mac(struct cnss_plat_data *plat_priv)
+{
+	u32 i;
+	int ret = 0;
+	struct cnss_plat_ipc_daemon_config *cfg;
+
+	ret = cnss_qmi_get_dms_mac(plat_priv);
+	if (ret == 0 && plat_priv->dms.mac_valid)
+		goto qmi_send;
+
+	/* DTSI property use-nv-mac is used to force DMS MAC address for WLAN.
+	 * Thus assert on failure to get MAC from DMS even after retries
+	 */
+	if (plat_priv->use_nv_mac) {
+		/* Check if Daemon says platform support DMS MAC provisioning */
+		cfg = cnss_plat_ipc_qmi_daemon_config();
+		if (cfg) {
+			if (!cfg->dms_mac_addr_supported) {
+				cnss_pr_err("DMS MAC address not supported\n");
+				CNSS_ASSERT(0);
+				return -EINVAL;
+			}
+		}
+		for (i = 0; i < CNSS_DMS_QMI_CONNECTION_WAIT_RETRY; i++) {
+			if (plat_priv->dms.mac_valid)
+				break;
+
+			ret = cnss_qmi_get_dms_mac(plat_priv);
+			if (ret == 0)
+				break;
+			msleep(CNSS_DMS_QMI_CONNECTION_WAIT_MS);
+		}
+		if (!plat_priv->dms.mac_valid) {
+			cnss_pr_err("Unable to get MAC from DMS after retries\n");
+			CNSS_ASSERT(0);
+			return -EINVAL;
+		}
+	}
+qmi_send:
+	if (plat_priv->dms.mac_valid)
+		ret =
+		cnss_wlfw_wlan_mac_req_send_sync(plat_priv, plat_priv->dms.mac,
+						 ARRAY_SIZE(plat_priv->dms.mac));
+
+	return ret;
+}
+
+static int cnss_cal_db_mem_update(struct cnss_plat_data *plat_priv,
+				  enum cnss_cal_db_op op, u32 *size)
+{
+	int ret = 0;
+	u32 timeout = cnss_get_timeout(plat_priv,
+				       CNSS_TIMEOUT_DAEMON_CONNECTION);
+	enum cnss_plat_ipc_qmi_client_id_v01 client_id =
+					CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01;
+
+	if (op >= CNSS_CAL_DB_INVALID_OP)
+		return -EINVAL;
+
+	if (!plat_priv->cbc_file_download) {
+		cnss_pr_info("CAL DB file not required as per BDF\n");
+		return 0;
+	}
+	if (*size == 0) {
+		cnss_pr_err("Invalid cal file size\n");
+		return -EINVAL;
+	}
+	if (!test_bit(CNSS_DAEMON_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_info("Waiting for CNSS Daemon connection\n");
+		ret = wait_for_completion_timeout(&plat_priv->daemon_connected,
+						  msecs_to_jiffies(timeout));
+		if (!ret) {
+			cnss_pr_err("Daemon not yet connected\n");
+			CNSS_ASSERT(0);
+			return ret;
+		}
+	}
+	if (!plat_priv->cal_mem->va) {
+		cnss_pr_err("CAL DB Memory not setup for FW\n");
+		return -EINVAL;
+	}
+
+	/* Copy CAL DB file contents to/from CAL_TYPE_DDR mem allocated to FW */
+	if (op == CNSS_CAL_DB_DOWNLOAD) {
+		cnss_pr_dbg("Initiating Calibration file download to mem\n");
+		ret = cnss_plat_ipc_qmi_file_download(client_id,
+						      CNSS_CAL_DB_FILE_NAME,
+						      plat_priv->cal_mem->va,
+						      size);
+	} else {
+		cnss_pr_dbg("Initiating Calibration mem upload to file\n");
+		ret = cnss_plat_ipc_qmi_file_upload(client_id,
+						    CNSS_CAL_DB_FILE_NAME,
+						    plat_priv->cal_mem->va,
+						    *size);
+	}
+
+	if (ret)
+		cnss_pr_err("Cal DB file %s %s failure\n",
+			    CNSS_CAL_DB_FILE_NAME,
+			    op == CNSS_CAL_DB_DOWNLOAD ? "download" : "upload");
+	else
+		cnss_pr_dbg("Cal DB file %s %s size %d done\n",
+			    CNSS_CAL_DB_FILE_NAME,
+			    op == CNSS_CAL_DB_DOWNLOAD ? "download" : "upload",
+			    *size);
+
+	return ret;
+}
+
+static int cnss_cal_mem_upload_to_file(struct cnss_plat_data *plat_priv)
+{
+	if (plat_priv->cal_file_size > plat_priv->cal_mem->size) {
+		cnss_pr_err("Cal file size is larger than Cal DB Mem size\n");
+		return -EINVAL;
+	}
+	return cnss_cal_db_mem_update(plat_priv, CNSS_CAL_DB_UPLOAD,
+				      &plat_priv->cal_file_size);
+}
+
+static int cnss_cal_file_download_to_mem(struct cnss_plat_data *plat_priv,
+					 u32 *cal_file_size)
+{
+	/* To download pass the total size of cal DB mem allocated.
+	 * After cal file is download to mem, its size is updated in
+	 * return pointer
+	 */
+	*cal_file_size = plat_priv->cal_mem->size;
+	return cnss_cal_db_mem_update(plat_priv, CNSS_CAL_DB_DOWNLOAD,
+				      cal_file_size);
+}
+
+static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	u32 cal_file_size = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_err("Reboot is in progress, ignore FW ready\n");
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Processing FW Init Done..\n");
+	del_timer(&plat_priv->fw_boot_timer);
+	set_bit(CNSS_FW_READY, &plat_priv->driver_state);
+	clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+
+	cnss_wlfw_send_pcie_gen_speed_sync(plat_priv);
+	cnss_send_subsys_restart_level_msg(plat_priv);
+
+	if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) {
+		clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	}
+
+	if (test_bit(ENABLE_WALTEST, &plat_priv->ctrl_params.quirks)) {
+		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+						    CNSS_WALTEST);
+	} else if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
+		cnss_request_antenna_sharing(plat_priv);
+		cnss_cal_file_download_to_mem(plat_priv, &cal_file_size);
+		cnss_wlfw_cal_report_req_send_sync(plat_priv, cal_file_size);
+		plat_priv->cal_time = jiffies;
+		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+						    CNSS_CALIBRATION);
+	} else {
+		ret = cnss_setup_dms_mac(plat_priv);
+		ret = cnss_bus_call_driver_probe(plat_priv);
+	}
+
+	if (ret && test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		goto out;
+	else if (ret)
+		goto shutdown;
+
+	cnss_vreg_unvote_type(plat_priv, CNSS_VREG_PRIM);
+
+	return 0;
+
+shutdown:
+	cnss_bus_dev_shutdown(plat_priv);
+
+	clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+	clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+
+out:
+	return ret;
+}
+
+static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
+{
+	switch (type) {
+	case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+		return "SERVER_ARRIVE";
+	case CNSS_DRIVER_EVENT_SERVER_EXIT:
+		return "SERVER_EXIT";
+	case CNSS_DRIVER_EVENT_REQUEST_MEM:
+		return "REQUEST_MEM";
+	case CNSS_DRIVER_EVENT_FW_MEM_READY:
+		return "FW_MEM_READY";
+	case CNSS_DRIVER_EVENT_FW_READY:
+		return "FW_READY";
+	case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+		return "COLD_BOOT_CAL_START";
+	case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+		return "COLD_BOOT_CAL_DONE";
+	case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+		return "REGISTER_DRIVER";
+	case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+		return "UNREGISTER_DRIVER";
+	case CNSS_DRIVER_EVENT_RECOVERY:
+		return "RECOVERY";
+	case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+		return "FORCE_FW_ASSERT";
+	case CNSS_DRIVER_EVENT_POWER_UP:
+		return "POWER_UP";
+	case CNSS_DRIVER_EVENT_POWER_DOWN:
+		return "POWER_DOWN";
+	case CNSS_DRIVER_EVENT_IDLE_RESTART:
+		return "IDLE_RESTART";
+	case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+		return "IDLE_SHUTDOWN";
+	case CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND:
+		return "IMS_WFC_CALL_IND";
+	case CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND:
+		return "WLFW_TWC_CFG_IND";
+	case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
+		return "QDSS_TRACE_REQ_MEM";
+	case CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE:
+		return "FW_MEM_FILE_SAVE";
+	case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE:
+		return "QDSS_TRACE_FREE";
+	case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA:
+		return "QDSS_TRACE_REQ_DATA";
+	case CNSS_DRIVER_EVENT_MAX:
+		return "EVENT_MAX";
+	}
+
+	return "UNKNOWN";
+};
+
+int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_event_type type,
+			   u32 flags, void *data)
+{
+	struct cnss_driver_event *event;
+	unsigned long irq_flags;
+	int gfp = GFP_KERNEL;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
+		    cnss_driver_event_to_str(type), type,
+		    flags ? "-sync" : "", plat_priv->driver_state, flags);
+
+	if (type >= CNSS_DRIVER_EVENT_MAX) {
+		cnss_pr_err("Invalid Event type: %d, can't post", type);
+		return -EINVAL;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		gfp = GFP_ATOMIC;
+
+	event = kzalloc(sizeof(*event), gfp);
+	if (!event)
+		return -ENOMEM;
+
+	cnss_pm_stay_awake(plat_priv);
+
+	event->type = type;
+	event->data = data;
+	init_completion(&event->complete);
+	event->ret = CNSS_EVENT_PENDING;
+	event->sync = !!(flags & CNSS_EVENT_SYNC);
+
+	spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+	list_add_tail(&event->list, &plat_priv->event_list);
+	spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+	queue_work(plat_priv->event_wq, &plat_priv->event_work);
+
+	if (!(flags & CNSS_EVENT_SYNC))
+		goto out;
+
+	if (flags & CNSS_EVENT_UNKILLABLE)
+		wait_for_completion(&event->complete);
+	else if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
+		ret = wait_for_completion_killable(&event->complete);
+	else
+		ret = wait_for_completion_interruptible(&event->complete);
+
+	cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
+		    cnss_driver_event_to_str(type), type,
+		    plat_priv->driver_state, ret, event->ret);
+	spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+	if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
+		event->sync = false;
+		spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+		ret = -EINTR;
+		goto out;
+	}
+	spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+	ret = event->ret;
+	kfree(event);
+
+out:
+	cnss_pm_relax(plat_priv);
+	return ret;
+}
+
+/**
+ * cnss_get_timeout - Get timeout for corresponding type.
+ * @plat_priv: Pointer to platform driver context.
+ * @cnss_timeout_type: Timeout type.
+ *
+ * Return: Timeout in milliseconds.
+ */
+unsigned int cnss_get_timeout(struct cnss_plat_data *plat_priv,
+			      enum cnss_timeout_type timeout_type)
+{
+	unsigned int qmi_timeout = cnss_get_qmi_timeout(plat_priv);
+
+	switch (timeout_type) {
+	case CNSS_TIMEOUT_QMI:
+		return qmi_timeout;
+	case CNSS_TIMEOUT_POWER_UP:
+		return (qmi_timeout << 2);
+	case CNSS_TIMEOUT_IDLE_RESTART:
+		/* In idle restart power up sequence, we have fw_boot_timer to
+		 * handle FW initialization failure.
+		 * It uses WLAN_MISSION_MODE_TIMEOUT, so setup 3x that time to
+		 * account for FW dump collection and FW re-initialization on
+		 * retry.
+		 */
+		return (qmi_timeout + WLAN_MISSION_MODE_TIMEOUT * 3);
+	case CNSS_TIMEOUT_CALIBRATION:
+		/* Similar to mission mode, in CBC if FW init fails
+		 * fw recovery is tried. Thus return 2x the CBC timeout.
+		 */
+		return (qmi_timeout + WLAN_COLD_BOOT_CAL_TIMEOUT * 2);
+	case CNSS_TIMEOUT_WLAN_WATCHDOG:
+		return ((qmi_timeout << 1) + WLAN_WD_TIMEOUT_MS);
+	case CNSS_TIMEOUT_RDDM:
+		return CNSS_RDDM_TIMEOUT_MS;
+	case CNSS_TIMEOUT_RECOVERY:
+		return RECOVERY_TIMEOUT;
+	case CNSS_TIMEOUT_DAEMON_CONNECTION:
+		return qmi_timeout + CNSS_DAEMON_CONNECT_TIMEOUT_MS;
+	default:
+		return qmi_timeout;
+	}
+}
+
+unsigned int cnss_get_boot_timeout(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return 0;
+	}
+
+	return cnss_get_timeout(plat_priv, CNSS_TIMEOUT_QMI);
+}
+EXPORT_SYMBOL(cnss_get_boot_timeout);
+
+int cnss_power_up(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	unsigned int timeout;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	cnss_pr_dbg("Powering up device\n");
+
+	ret = cnss_driver_event_post(plat_priv,
+				     CNSS_DRIVER_EVENT_POWER_UP,
+				     CNSS_EVENT_SYNC, NULL);
+	if (ret)
+		goto out;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		goto out;
+
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_POWER_UP);
+
+	reinit_completion(&plat_priv->power_up_complete);
+	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+					  msecs_to_jiffies(timeout));
+	if (!ret) {
+		cnss_pr_err("Timeout (%ums) waiting for power up to complete\n",
+			    timeout);
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	cnss_pr_dbg("Powering down device\n");
+
+	return cnss_driver_event_post(plat_priv,
+				      CNSS_DRIVER_EVENT_POWER_DOWN,
+				      CNSS_EVENT_SYNC, NULL);
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+int cnss_idle_restart(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	unsigned int timeout;
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!mutex_trylock(&plat_priv->driver_ops_lock)) {
+		cnss_pr_dbg("Another driver operation is in progress, ignore idle restart\n");
+		return -EBUSY;
+	}
+
+	cnss_pr_dbg("Doing idle restart\n");
+
+	reinit_completion(&plat_priv->power_up_complete);
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Reboot or shutdown is in progress, ignore idle restart\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cnss_driver_event_post(plat_priv,
+				     CNSS_DRIVER_EVENT_IDLE_RESTART,
+				     CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+	if (ret == -EINTR && plat_priv->device_id != QCA6174_DEVICE_ID)
+		cnss_pr_err("Idle restart has been interrupted but device power up is still in progress");
+	else if (ret)
+		goto out;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
+		ret = cnss_bus_call_driver_probe(plat_priv);
+		goto out;
+	}
+
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_IDLE_RESTART);
+	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+					  msecs_to_jiffies(timeout));
+	if (plat_priv->power_up_error) {
+		ret = plat_priv->power_up_error;
+		clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);
+		cnss_pr_dbg("Power up error:%d, exiting\n",
+			    plat_priv->power_up_error);
+		goto out;
+	}
+
+	if (!ret) {
+		/* This exception occurs after attempting retry of FW recovery.
+		 * Thus we can safely power off the device.
+		 */
+		cnss_fatal_err("Timeout (%ums) waiting for idle restart to complete\n",
+			       timeout);
+		ret = -ETIMEDOUT;
+		cnss_power_down(dev);
+		CNSS_ASSERT(0);
+		goto out;
+	}
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Reboot or shutdown is in progress, ignore idle restart\n");
+		del_timer(&plat_priv->fw_boot_timer);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* In non-DRV mode, remove MHI satellite configuration. Switching to
+	 * non-DRV is supported only once after device reboots and before wifi
+	 * is turned on. We do not allow switching back to DRV.
+	 * To bring device back into DRV, user needs to reboot device.
+	 */
+	if (test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks)) {
+		cnss_pr_dbg("DRV is disabled\n");
+		cnss_bus_disable_mhi_satellite_cfg(plat_priv);
+	}
+
+	mutex_unlock(&plat_priv->driver_ops_lock);
+	return 0;
+
+out:
+	mutex_unlock(&plat_priv->driver_ops_lock);
+	return ret;
+}
+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);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (test_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state)) {
+		cnss_pr_dbg("System suspend or resume in progress, ignore idle shutdown\n");
+		return -EAGAIN;
+	}
+
+	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)) {
+		cnss_pr_dbg("Recovery in progress. Ignore IDLE Shutdown\n");
+		return -EBUSY;
+	}
+
+	return cnss_driver_event_post(plat_priv,
+				      CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+				      CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_idle_shutdown);
+
+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 < 0) {
+		cnss_pr_err("Failed to get vreg, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_get_clk(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get clocks, err = %d\n", ret);
+		goto put_vreg;
+	}
+
+	ret = cnss_get_pinctrl(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+		goto put_clk;
+	}
+
+	return 0;
+
+put_clk:
+	cnss_put_clk(plat_priv);
+put_vreg:
+	cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM);
+out:
+	return ret;
+}
+
+static void cnss_put_resources(struct cnss_plat_data *plat_priv)
+{
+	cnss_put_clk(plat_priv);
+	cnss_put_vreg_type(plat_priv, CNSS_VREG_PRIM);
+}
+
+#if IS_ENABLED(CONFIG_ESOC) && IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+static int cnss_modem_notifier_nb(struct notifier_block *nb,
+				  unsigned long code,
+				  void *ss_handle)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(nb, struct cnss_plat_data, modem_nb);
+	struct cnss_esoc_info *esoc_info;
+
+	cnss_pr_dbg("Modem notifier: event %lu\n", code);
+
+	if (!plat_priv)
+		return NOTIFY_DONE;
+
+	esoc_info = &plat_priv->esoc_info;
+
+	if (code == SUBSYS_AFTER_POWERUP)
+		esoc_info->modem_current_status = 1;
+	else if (code == SUBSYS_BEFORE_SHUTDOWN)
+		esoc_info->modem_current_status = 0;
+	else
+		return NOTIFY_DONE;
+
+	if (!cnss_bus_call_driver_modem_status(plat_priv,
+					       esoc_info->modem_current_status))
+		return NOTIFY_DONE;
+
+	return NOTIFY_OK;
+}
+
+static int cnss_register_esoc(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_esoc_info *esoc_info;
+	struct esoc_desc *esoc_desc;
+	const char *client_desc;
+
+	dev = &plat_priv->plat_dev->dev;
+	esoc_info = &plat_priv->esoc_info;
+
+	esoc_info->notify_modem_status =
+		of_property_read_bool(dev->of_node,
+				      "qcom,notify-modem-status");
+
+	if (!esoc_info->notify_modem_status)
+		goto out;
+
+	ret = of_property_read_string_index(dev->of_node, "esoc-names", 0,
+					    &client_desc);
+	if (ret) {
+		cnss_pr_dbg("esoc-names is not defined in DT, skip!\n");
+	} else {
+		esoc_desc = devm_register_esoc_client(dev, client_desc);
+		if (IS_ERR_OR_NULL(esoc_desc)) {
+			ret = PTR_RET(esoc_desc);
+			cnss_pr_err("Failed to register esoc_desc, err = %d\n",
+				    ret);
+			goto out;
+		}
+		esoc_info->esoc_desc = esoc_desc;
+	}
+
+	plat_priv->modem_nb.notifier_call = cnss_modem_notifier_nb;
+	esoc_info->modem_current_status = 0;
+	esoc_info->modem_notify_handler =
+		subsys_notif_register_notifier(esoc_info->esoc_desc ?
+					       esoc_info->esoc_desc->name :
+					       "modem", &plat_priv->modem_nb);
+	if (IS_ERR(esoc_info->modem_notify_handler)) {
+		ret = PTR_ERR(esoc_info->modem_notify_handler);
+		cnss_pr_err("Failed to register esoc notifier, err = %d\n",
+			    ret);
+		goto unreg_esoc;
+	}
+
+	return 0;
+unreg_esoc:
+	if (esoc_info->esoc_desc)
+		devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+out:
+	return ret;
+}
+
+static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct cnss_esoc_info *esoc_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	esoc_info = &plat_priv->esoc_info;
+
+	if (esoc_info->notify_modem_status)
+		subsys_notif_unregister_notifier
+		(esoc_info->modem_notify_handler,
+		 &plat_priv->modem_nb);
+	if (esoc_info->esoc_desc)
+		devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+}
+#else
+static inline int cnss_register_esoc(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline void cnss_unregister_esoc(struct cnss_plat_data *plat_priv) {}
+#endif
+
+int cnss_enable_dev_sol_irq(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+	int ret = 0;
+
+	if (sol_gpio->dev_sol_gpio < 0 || sol_gpio->dev_sol_irq <= 0)
+		return 0;
+
+	ret = enable_irq_wake(sol_gpio->dev_sol_irq);
+	if (ret)
+		cnss_pr_err("Failed to enable device SOL as wake IRQ, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+int cnss_disable_dev_sol_irq(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+	int ret = 0;
+
+	if (sol_gpio->dev_sol_gpio < 0 || sol_gpio->dev_sol_irq <= 0)
+		return 0;
+
+	ret = disable_irq_wake(sol_gpio->dev_sol_irq);
+	if (ret)
+		cnss_pr_err("Failed to disable device SOL as wake IRQ, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+int cnss_get_dev_sol_value(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (sol_gpio->dev_sol_gpio < 0)
+		return -EINVAL;
+
+	return gpio_get_value(sol_gpio->dev_sol_gpio);
+}
+
+static irqreturn_t cnss_dev_sol_handler(int irq, void *data)
+{
+	struct cnss_plat_data *plat_priv = data;
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (test_bit(CNSS_POWER_OFF, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Ignore Dev SOL during device power off");
+		return IRQ_HANDLED;
+	}
+
+	sol_gpio->dev_sol_counter++;
+	cnss_pr_dbg("WLAN device SOL IRQ (%u) is asserted #%u, dev_sol_val: %d\n",
+		    irq, sol_gpio->dev_sol_counter,
+		    cnss_get_dev_sol_value(plat_priv));
+
+	/* Make sure abort current suspend */
+	cnss_pm_stay_awake(plat_priv);
+	cnss_pm_relax(plat_priv);
+	pm_system_wakeup();
+
+	cnss_bus_handle_dev_sol_irq(plat_priv);
+
+	return IRQ_HANDLED;
+}
+
+static int cnss_init_dev_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+	int ret = 0;
+
+	sol_gpio->dev_sol_gpio = of_get_named_gpio(dev->of_node,
+						   "wlan-dev-sol-gpio", 0);
+	if (sol_gpio->dev_sol_gpio < 0)
+		goto out;
+
+	cnss_pr_dbg("Get device SOL GPIO (%d) from device node\n",
+		    sol_gpio->dev_sol_gpio);
+
+	ret = gpio_request(sol_gpio->dev_sol_gpio, "wlan_dev_sol_gpio");
+	if (ret) {
+		cnss_pr_err("Failed to request device SOL GPIO, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	gpio_direction_input(sol_gpio->dev_sol_gpio);
+	sol_gpio->dev_sol_irq = gpio_to_irq(sol_gpio->dev_sol_gpio);
+
+	ret = request_irq(sol_gpio->dev_sol_irq, cnss_dev_sol_handler,
+			  IRQF_TRIGGER_FALLING, "wlan_dev_sol_irq", plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to request device SOL IRQ, err = %d\n", ret);
+		goto free_gpio;
+	}
+
+	return 0;
+
+free_gpio:
+	gpio_free(sol_gpio->dev_sol_gpio);
+out:
+	return ret;
+}
+
+static void cnss_deinit_dev_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (sol_gpio->dev_sol_gpio < 0)
+		return;
+
+	free_irq(sol_gpio->dev_sol_irq, plat_priv);
+	gpio_free(sol_gpio->dev_sol_gpio);
+}
+
+int cnss_set_host_sol_value(struct cnss_plat_data *plat_priv, int value)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (sol_gpio->host_sol_gpio < 0)
+		return -EINVAL;
+
+	if (value)
+		cnss_pr_dbg("Assert host SOL GPIO\n");
+	gpio_set_value(sol_gpio->host_sol_gpio, value);
+
+	return 0;
+}
+
+int cnss_get_host_sol_value(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (sol_gpio->host_sol_gpio < 0)
+		return -EINVAL;
+
+	return gpio_get_value(sol_gpio->host_sol_gpio);
+}
+
+static int cnss_init_host_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+	int ret = 0;
+
+	sol_gpio->host_sol_gpio = of_get_named_gpio(dev->of_node,
+						    "wlan-host-sol-gpio", 0);
+	if (sol_gpio->host_sol_gpio < 0)
+		goto out;
+
+	cnss_pr_dbg("Get host SOL GPIO (%d) from device node\n",
+		    sol_gpio->host_sol_gpio);
+
+	ret = gpio_request(sol_gpio->host_sol_gpio, "wlan_host_sol_gpio");
+	if (ret) {
+		cnss_pr_err("Failed to request host SOL GPIO, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	gpio_direction_output(sol_gpio->host_sol_gpio, 0);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static void cnss_deinit_host_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_sol_gpio *sol_gpio = &plat_priv->sol_gpio;
+
+	if (sol_gpio->host_sol_gpio < 0)
+		return;
+
+	gpio_free(sol_gpio->host_sol_gpio);
+}
+
+static int cnss_init_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	ret = cnss_init_dev_sol_gpio(plat_priv);
+	if (ret)
+		goto out;
+
+	ret = cnss_init_host_sol_gpio(plat_priv);
+	if (ret)
+		goto deinit_dev_sol;
+
+	return 0;
+
+deinit_dev_sol:
+	cnss_deinit_dev_sol_gpio(plat_priv);
+out:
+	return ret;
+}
+
+static void cnss_deinit_sol_gpio(struct cnss_plat_data *plat_priv)
+{
+	cnss_deinit_host_sol_gpio(plat_priv);
+	cnss_deinit_dev_sol_gpio(plat_priv);
+}
+
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
+{
+	struct cnss_plat_data *plat_priv;
+	int ret = 0;
+
+	if (!subsys_desc->dev) {
+		cnss_pr_err("dev from subsys_desc is NULL\n");
+		return -ENODEV;
+	}
+
+	plat_priv = dev_get_drvdata(subsys_desc->dev);
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_dbg("subsys powerup is ignored\n");
+		return 0;
+	}
+
+	ret = cnss_bus_dev_powerup(plat_priv);
+	if (ret)
+		__pm_relax(plat_priv->recovery_ws);
+	return ret;
+}
+
+static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
+				bool force_stop)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!subsys_desc->dev) {
+		cnss_pr_err("dev from subsys_desc is NULL\n");
+		return -ENODEV;
+	}
+
+	plat_priv = dev_get_drvdata(subsys_desc->dev);
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_dbg("subsys shutdown is ignored\n");
+		return 0;
+	}
+
+	return cnss_bus_dev_shutdown(plat_priv);
+}
+
+void cnss_device_crashed(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_subsys_info *subsys_info;
+
+	if (!plat_priv)
+		return;
+
+	subsys_info = &plat_priv->subsys_info;
+	if (subsys_info->subsys_device) {
+		set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		subsys_set_crash_status(subsys_info->subsys_device, true);
+		subsystem_restart_dev(subsys_info->subsys_device);
+	}
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return;
+	}
+
+	cnss_bus_dev_crash_shutdown(plat_priv);
+}
+
+static int cnss_subsys_ramdump(int enable,
+			       const struct subsys_desc *subsys_desc)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!enable)
+		return 0;
+
+	return cnss_bus_dev_ramdump(plat_priv);
+}
+
+static void cnss_recovery_work_handler(struct work_struct *work)
+{
+}
+#else
+void cnss_recovery_handler(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+
+	if (!plat_priv->recovery_enabled)
+		panic("subsys-restart: Resetting the SoC wlan crashed\n");
+
+	cnss_bus_dev_shutdown(plat_priv);
+	cnss_bus_dev_ramdump(plat_priv);
+
+	/* If recovery is triggered before Host driver registration,
+	 * avoid device power up because eventually device will be
+	 * power up as part of driver registration.
+	 */
+	if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) ||
+	    !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n",
+			    plat_priv->driver_state);
+		return;
+	}
+
+	msleep(POWER_RESET_MIN_DELAY_MS);
+
+	ret = cnss_bus_dev_powerup(plat_priv);
+	if (ret) {
+		__pm_relax(plat_priv->recovery_ws);
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	}
+
+	return;
+}
+
+static void cnss_recovery_work_handler(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(work, struct cnss_plat_data, recovery_work);
+
+	cnss_recovery_handler(plat_priv);
+}
+
+void cnss_device_crashed(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return;
+
+	set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	schedule_work(&plat_priv->recovery_work);
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
+void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_ramdump_info *ramdump_info;
+
+	if (!plat_priv)
+		return NULL;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	*size = ramdump_info->ramdump_size;
+
+	return ramdump_info->ramdump_va;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
+{
+	switch (reason) {
+	case CNSS_REASON_DEFAULT:
+		return "DEFAULT";
+	case CNSS_REASON_LINK_DOWN:
+		return "LINK_DOWN";
+	case CNSS_REASON_RDDM:
+		return "RDDM";
+	case CNSS_REASON_TIMEOUT:
+		return "TIMEOUT";
+	}
+
+	return "UNKNOWN";
+};
+
+static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
+			    enum cnss_recovery_reason reason)
+{
+	int ret;
+
+	plat_priv->recovery_count++;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		goto self_recovery;
+
+	if (test_bit(SKIP_RECOVERY, &plat_priv->ctrl_params.quirks)) {
+		cnss_pr_dbg("Skip device recovery\n");
+		return 0;
+	}
+
+	/* FW recovery sequence has multiple steps and firmware load requires
+	 * linux PM in awake state. Thus hold the cnss wake source until
+	 * WLAN MISSION enabled. CNSS_TIMEOUT_RECOVERY option should cover all
+	 * time taken in this process.
+	 */
+	pm_wakeup_ws_event(plat_priv->recovery_ws,
+			   cnss_get_timeout(plat_priv, CNSS_TIMEOUT_RECOVERY),
+			   true);
+
+	switch (reason) {
+	case CNSS_REASON_LINK_DOWN:
+		if (!cnss_bus_check_link_status(plat_priv)) {
+			cnss_pr_dbg("Skip link down recovery as link is already up\n");
+			return 0;
+		}
+		if (test_bit(LINK_DOWN_SELF_RECOVERY,
+			     &plat_priv->ctrl_params.quirks))
+			goto self_recovery;
+		if (!cnss_bus_recover_link_down(plat_priv)) {
+			/* clear recovery bit here to avoid skipping
+			 * the recovery work for RDDM later
+			 */
+			clear_bit(CNSS_DRIVER_RECOVERY,
+				  &plat_priv->driver_state);
+			return 0;
+		}
+		break;
+	case CNSS_REASON_RDDM:
+		cnss_bus_collect_dump_info(plat_priv, false);
+		break;
+	case CNSS_REASON_DEFAULT:
+	case CNSS_REASON_TIMEOUT:
+		break;
+	default:
+		cnss_pr_err("Unsupported recovery reason: %s(%d)\n",
+			    cnss_recovery_reason_to_str(reason), reason);
+		break;
+	}
+	cnss_bus_device_crashed(plat_priv);
+
+	return 0;
+
+self_recovery:
+	cnss_pr_dbg("Going for self recovery\n");
+	cnss_bus_dev_shutdown(plat_priv);
+
+	if (test_bit(LINK_DOWN_SELF_RECOVERY, &plat_priv->ctrl_params.quirks))
+		clear_bit(LINK_DOWN_SELF_RECOVERY,
+			  &plat_priv->ctrl_params.quirks);
+
+	/* If link down self recovery is triggered before Host driver
+	 * registration, avoid device power up because eventually device
+	 * will be power up as part of driver registration.
+	 */
+
+	if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) ||
+	    !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n",
+			    plat_priv->driver_state);
+		return 0;
+	}
+
+	ret = cnss_bus_dev_powerup(plat_priv);
+	if (ret)
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+
+	return 0;
+}
+
+static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
+				     void *data)
+{
+	struct cnss_recovery_data *recovery_data = data;
+	int ret = 0;
+
+	cnss_pr_dbg("Driver recovery is triggered with reason: %s(%d)\n",
+		    cnss_recovery_reason_to_str(recovery_data->reason),
+		    recovery_data->reason);
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_err("Improper driver state, ignore recovery\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_err("Reboot is in progress, ignore recovery\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_err("Recovery is already in progress\n");
+		CNSS_ASSERT(0);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
+		cnss_pr_err("Driver unload or idle shutdown is in progress, ignore recovery\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+		    test_bit(CNSS_DRIVER_IDLE_RESTART,
+			     &plat_priv->driver_state)) {
+			cnss_pr_err("Driver load or idle restart is in progress, ignore recovery\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+	default:
+		if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+			set_bit(CNSS_FW_BOOT_RECOVERY,
+				&plat_priv->driver_state);
+		}
+		break;
+	}
+
+	set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	ret = cnss_do_recovery(plat_priv, recovery_data->reason);
+
+out:
+	kfree(data);
+	return ret;
+}
+
+int cnss_self_recovery(struct device *dev,
+		       enum cnss_recovery_reason reason)
+{
+	cnss_schedule_recovery(dev, reason);
+	return 0;
+}
+EXPORT_SYMBOL(cnss_self_recovery);
+
+void cnss_schedule_recovery(struct device *dev,
+			    enum cnss_recovery_reason reason)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_recovery_data *data;
+	int gfp = GFP_KERNEL;
+
+	if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
+
+	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Driver unload or idle shutdown is in progress, ignore schedule recovery\n");
+		return;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		gfp = GFP_ATOMIC;
+
+	data = kzalloc(sizeof(*data), gfp);
+	if (!data)
+		return;
+
+	data->reason = reason;
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_RECOVERY,
+			       0, data);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery);
+
+int cnss_force_fw_assert(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
+		cnss_pr_info("Forced FW assert is not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (cnss_bus_is_device_down(plat_priv)) {
+		cnss_pr_info("Device is already in bad state, ignore force assert\n");
+		return 0;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
+		return 0;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+				       0, NULL);
+	else
+		cnss_bus_force_fw_assert_hdlr(plat_priv);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_force_fw_assert);
+
+int cnss_force_collect_rddm(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	unsigned int timeout;
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
+		cnss_pr_info("Force collect rddm is not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (cnss_bus_is_device_down(plat_priv)) {
+		cnss_pr_info("Device is already in bad state, wait to collect rddm\n");
+		goto wait_rddm;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_info("Recovery is already in progress, wait to collect rddm\n");
+		goto wait_rddm;
+	}
+
+	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
+		cnss_pr_info("Loading/Unloading/idle restart/shutdown is in progress, ignore forced collect rddm\n");
+		return 0;
+	}
+
+	ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
+	if (ret)
+		return ret;
+
+wait_rddm:
+	reinit_completion(&plat_priv->rddm_complete);
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_RDDM);
+	ret = wait_for_completion_timeout(&plat_priv->rddm_complete,
+					  msecs_to_jiffies(timeout));
+	if (!ret) {
+		cnss_pr_err("Timeout (%ums) waiting for RDDM to complete\n",
+			    timeout);
+		ret = -ETIMEDOUT;
+	} else if (ret > 0) {
+		ret = 0;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_force_collect_rddm);
+
+int cnss_qmi_send_get(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state))
+		return 0;
+
+	return cnss_bus_qmi_send_get(plat_priv);
+}
+EXPORT_SYMBOL(cnss_qmi_send_get);
+
+int cnss_qmi_send_put(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state))
+		return 0;
+
+	return cnss_bus_qmi_send_put(plat_priv);
+}
+EXPORT_SYMBOL(cnss_qmi_send_put);
+
+int cnss_qmi_send(struct device *dev, int type, void *cmd,
+		  int cmd_len, void *cb_ctx,
+		  int (*cb)(void *ctx, void *event, int event_len))
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state))
+		return -EINVAL;
+
+	plat_priv->get_info_cb = cb;
+	plat_priv->get_info_cb_ctx = cb_ctx;
+
+	ret = cnss_wlfw_get_info_send_sync(plat_priv, type, cmd, cmd_len);
+	if (ret) {
+		plat_priv->get_info_cb = NULL;
+		plat_priv->get_info_cb_ctx = NULL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_qmi_send);
+
+int cnss_register_driver_async_data_cb(struct device *dev, void *cb_ctx,
+				       int (*cb)(void *ctx, uint16_t type,
+						 void *event, int event_len))
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state))
+		return -EINVAL;
+
+	plat_priv->get_driver_async_data_cb = cb;
+	plat_priv->get_driver_async_data_ctx = cb_ctx;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_register_driver_async_data_cb);
+
+static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	u32 retry = 0, timeout;
+
+	if (test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Calibration complete. Ignore calibration req\n");
+		goto out;
+	} else if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Calibration in progress. Ignore new calibration req\n");
+		goto out;
+	} else if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Calibration deferred as WLAN device disabled\n");
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state) ||
+	    test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("WLAN in mission mode before cold boot calibration\n");
+		CNSS_ASSERT(0);
+		return -EINVAL;
+	}
+
+	while (retry++ < CNSS_CAL_START_PROBE_WAIT_RETRY_MAX) {
+		if (test_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state))
+			break;
+		msleep(CNSS_CAL_START_PROBE_WAIT_MS);
+
+		if (retry == CNSS_CAL_START_PROBE_WAIT_RETRY_MAX) {
+			cnss_pr_err("Calibration start failed as PCI probe not complete\n");
+			CNSS_ASSERT(0);
+			ret = -EINVAL;
+			goto mark_cal_fail;
+		}
+	}
+
+	switch (plat_priv->device_id) {
+	case QCA6290_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		cnss_pr_err("Not supported for device ID 0x%lx\n",
+			    plat_priv->device_id);
+		ret = -EINVAL;
+		goto mark_cal_fail;
+	}
+
+	set_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
+	if (test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state)) {
+		timeout = cnss_get_timeout(plat_priv,
+					   CNSS_TIMEOUT_CALIBRATION);
+		cnss_pr_dbg("Restarting calibration %ds timeout\n",
+			    timeout / 1000);
+		if (cancel_delayed_work_sync(&plat_priv->wlan_reg_driver_work))
+			schedule_delayed_work(&plat_priv->wlan_reg_driver_work,
+					      msecs_to_jiffies(timeout));
+	}
+	reinit_completion(&plat_priv->cal_complete);
+	ret = cnss_bus_dev_powerup(plat_priv);
+mark_cal_fail:
+	if (ret) {
+		complete(&plat_priv->cal_complete);
+		clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
+		/* Set CBC done in driver state to mark attempt and note error
+		 * since calibration cannot be retried at boot.
+		 */
+		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:
+	return ret;
+}
+
+static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
+					void *data)
+{
+	struct cnss_cal_info *cal_info = data;
+
+	if (!test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+	    test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state))
+		goto out;
+
+	switch (cal_info->cal_status) {
+	case CNSS_CAL_DONE:
+		cnss_pr_dbg("Calibration completed successfully\n");
+		plat_priv->cal_done = true;
+		break;
+	case CNSS_CAL_TIMEOUT:
+	case CNSS_CAL_FAILURE:
+		cnss_pr_dbg("Calibration failed. Status: %d, force shutdown\n",
+			    cal_info->cal_status);
+		break;
+	default:
+		cnss_pr_err("Unknown calibration status: %u\n",
+			    cal_info->cal_status);
+		break;
+	}
+
+	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);
+
+	if (cal_info->cal_status == CNSS_CAL_DONE) {
+		cnss_cal_mem_upload_to_file(plat_priv);
+		if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state))
+			goto out;
+
+		cnss_pr_dbg("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:
+	kfree(data);
+	return 0;
+}
+
+static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	ret = cnss_bus_dev_powerup(plat_priv);
+	if (ret)
+		clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);
+
+	return ret;
+}
+
+static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
+{
+	cnss_bus_dev_shutdown(plat_priv);
+
+	return 0;
+}
+
+static int cnss_qdss_trace_req_mem_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	ret = cnss_bus_alloc_qdss_mem(plat_priv);
+	if (ret < 0)
+		return ret;
+
+	return cnss_wlfw_qdss_trace_mem_info_send_sync(plat_priv);
+}
+
+static void *cnss_get_fw_mem_pa_to_va(struct cnss_fw_mem *fw_mem,
+				      u32 mem_seg_len, u64 pa, u32 size)
+{
+	int i = 0;
+	u64 offset = 0;
+	void *va = NULL;
+	u64 local_pa;
+	u32 local_size;
+
+	for (i = 0; i < mem_seg_len; i++) {
+		if (i == QMI_WLFW_MEM_LPASS_SHARED_V01)
+			continue;
+
+		local_pa = (u64)fw_mem[i].pa;
+		local_size = (u32)fw_mem[i].size;
+		if (pa == local_pa && size <= local_size) {
+			va = fw_mem[i].va;
+			break;
+		}
+		if (pa > local_pa &&
+		    pa < local_pa + local_size &&
+		    pa + size <= local_pa + local_size) {
+			offset = pa - local_pa;
+			va = fw_mem[i].va + offset;
+			break;
+		}
+	}
+	return va;
+}
+
+static int cnss_fw_mem_file_save_hdlr(struct cnss_plat_data *plat_priv,
+				      void *data)
+{
+	struct cnss_qmi_event_fw_mem_file_save_data *event_data = data;
+	struct cnss_fw_mem *fw_mem_seg;
+	int ret = 0L;
+	void *va = NULL;
+	u32 i, fw_mem_seg_len;
+
+	switch (event_data->mem_type) {
+	case QMI_WLFW_MEM_TYPE_DDR_V01:
+		if (!plat_priv->fw_mem_seg_len)
+			goto invalid_mem_save;
+
+		fw_mem_seg = plat_priv->fw_mem;
+		fw_mem_seg_len = plat_priv->fw_mem_seg_len;
+		break;
+	case QMI_WLFW_MEM_QDSS_V01:
+		if (!plat_priv->qdss_mem_seg_len)
+			goto invalid_mem_save;
+
+		fw_mem_seg = plat_priv->qdss_mem;
+		fw_mem_seg_len = plat_priv->qdss_mem_seg_len;
+		break;
+	default:
+		goto invalid_mem_save;
+	}
+
+	for (i = 0; i < event_data->mem_seg_len; i++) {
+		va = cnss_get_fw_mem_pa_to_va(fw_mem_seg, fw_mem_seg_len,
+					      event_data->mem_seg[i].addr,
+					      event_data->mem_seg[i].size);
+		if (!va) {
+			cnss_pr_err("Fail to find matching va of pa %pa for mem type: %d\n",
+				    &event_data->mem_seg[i].addr,
+				    event_data->mem_type);
+			ret = -EINVAL;
+			break;
+		}
+		ret = cnss_genl_send_msg(va, CNSS_GENL_MSG_TYPE_QDSS,
+					 event_data->file_name,
+					 event_data->mem_seg[i].size);
+		if (ret < 0) {
+			cnss_pr_err("Fail to save fw mem data: %d\n",
+				    ret);
+			break;
+		}
+	}
+	kfree(data);
+	return ret;
+
+invalid_mem_save:
+	cnss_pr_err("FW Mem type %d not allocated. Invalid save request\n",
+		    event_data->mem_type);
+	kfree(data);
+	return -EINVAL;
+}
+
+static int cnss_qdss_trace_free_hdlr(struct cnss_plat_data *plat_priv)
+{
+	cnss_bus_free_qdss_mem(plat_priv);
+
+	return 0;
+}
+
+static int cnss_qdss_trace_req_data_hdlr(struct cnss_plat_data *plat_priv,
+					 void *data)
+{
+	int ret = 0;
+	struct cnss_qmi_event_fw_mem_file_save_data *event_data = data;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	ret = cnss_wlfw_qdss_data_send_sync(plat_priv, event_data->file_name,
+					    event_data->total_size);
+
+	kfree(data);
+	return ret;
+}
+
+static void cnss_driver_event_work(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(work, struct cnss_plat_data, event_work);
+	struct cnss_driver_event *event;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	cnss_pm_stay_awake(plat_priv);
+
+	spin_lock_irqsave(&plat_priv->event_lock, flags);
+
+	while (!list_empty(&plat_priv->event_list)) {
+		event = list_first_entry(&plat_priv->event_list,
+					 struct cnss_driver_event, list);
+		list_del(&event->list);
+		spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+		cnss_pr_dbg("Processing driver event: %s%s(%d), state: 0x%lx\n",
+			    cnss_driver_event_to_str(event->type),
+			    event->sync ? "-sync" : "", event->type,
+			    plat_priv->driver_state);
+
+		switch (event->type) {
+		case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+			ret = cnss_wlfw_server_arrive(plat_priv, event->data);
+			break;
+		case CNSS_DRIVER_EVENT_SERVER_EXIT:
+			ret = cnss_wlfw_server_exit(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_REQUEST_MEM:
+			ret = cnss_bus_alloc_fw_mem(plat_priv);
+			if (ret)
+				break;
+			ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_FW_MEM_READY:
+			ret = cnss_fw_mem_ready_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_FW_READY:
+			ret = cnss_fw_ready_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+			ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+			ret = cnss_cold_boot_cal_done_hdlr(plat_priv,
+							   event->data);
+			break;
+		case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+			ret = cnss_bus_register_driver_hdlr(plat_priv,
+							    event->data);
+			break;
+		case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+			ret = cnss_bus_unregister_driver_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_RECOVERY:
+			ret = cnss_driver_recovery_hdlr(plat_priv,
+							event->data);
+			break;
+		case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+			ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_IDLE_RESTART:
+			set_bit(CNSS_DRIVER_IDLE_RESTART,
+				&plat_priv->driver_state);
+			fallthrough;
+		case CNSS_DRIVER_EVENT_POWER_UP:
+			ret = cnss_power_up_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+			set_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
+				&plat_priv->driver_state);
+			fallthrough;
+		case CNSS_DRIVER_EVENT_POWER_DOWN:
+			ret = cnss_power_down_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND:
+			ret = cnss_process_wfc_call_ind_event(plat_priv,
+							      event->data);
+			break;
+		case CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND:
+			ret = cnss_process_twt_cfg_ind_event(plat_priv,
+							     event->data);
+			break;
+		case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM:
+			ret = cnss_qdss_trace_req_mem_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE:
+			ret = cnss_fw_mem_file_save_hdlr(plat_priv,
+							 event->data);
+			break;
+		case CNSS_DRIVER_EVENT_QDSS_TRACE_FREE:
+			ret = cnss_qdss_trace_free_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA:
+			ret = cnss_qdss_trace_req_data_hdlr(plat_priv,
+							    event->data);
+			break;
+		default:
+			cnss_pr_err("Invalid driver event type: %d",
+				    event->type);
+			kfree(event);
+			spin_lock_irqsave(&plat_priv->event_lock, flags);
+			continue;
+		}
+
+		spin_lock_irqsave(&plat_priv->event_lock, flags);
+		if (event->sync) {
+			event->ret = ret;
+			complete(&event->complete);
+			continue;
+		}
+		spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+		kfree(event);
+
+		spin_lock_irqsave(&plat_priv->event_lock, flags);
+	}
+	spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+	cnss_pm_relax(plat_priv);
+}
+
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+int cnss_register_subsys(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_subsys_info *subsys_info;
+
+	subsys_info = &plat_priv->subsys_info;
+
+	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;
+	subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump;
+	subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown;
+	subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev;
+
+	subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc);
+	if (IS_ERR(subsys_info->subsys_device)) {
+		ret = PTR_ERR(subsys_info->subsys_device);
+		cnss_pr_err("Failed to register subsys, err = %d\n", ret);
+		goto out;
+	}
+
+	subsys_info->subsys_handle =
+		subsystem_get(subsys_info->subsys_desc.name);
+	if (!subsys_info->subsys_handle) {
+		cnss_pr_err("Failed to get subsys_handle!\n");
+		ret = -EINVAL;
+		goto unregister_subsys;
+	} else if (IS_ERR(subsys_info->subsys_handle)) {
+		ret = PTR_ERR(subsys_info->subsys_handle);
+		cnss_pr_err("Failed to do subsystem_get, err = %d\n", ret);
+		goto unregister_subsys;
+	}
+
+	return 0;
+
+unregister_subsys:
+	subsys_unregister(subsys_info->subsys_device);
+out:
+	return ret;
+}
+
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_subsys_info *subsys_info;
+
+	subsys_info = &plat_priv->subsys_info;
+	subsystem_put(subsys_info->subsys_handle);
+	subsys_unregister(subsys_info->subsys_device);
+}
+
+static void *cnss_create_ramdump_device(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_subsys_info *subsys_info = &plat_priv->subsys_info;
+
+	return create_ramdump_device(subsys_info->subsys_desc.name,
+				     subsys_info->subsys_desc.dev);
+}
+
+static void cnss_destroy_ramdump_device(struct cnss_plat_data *plat_priv,
+					void *ramdump_dev)
+{
+	destroy_ramdump_device(ramdump_dev);
+}
+
+int cnss_do_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info *ramdump_info = &plat_priv->ramdump_info;
+	struct ramdump_segment segment;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = (void __iomem *)ramdump_info->ramdump_va;
+	segment.size = ramdump_info->ramdump_size;
+
+	return qcom_ramdump(ramdump_info->ramdump_dev, &segment, 1);
+}
+
+int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+	struct cnss_dump_data *dump_data = &info_v2->dump_data;
+	struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+	struct ramdump_segment *ramdump_segs, *s;
+	struct cnss_dump_meta_info meta_info = {0};
+	int i, ret = 0;
+
+	ramdump_segs = kcalloc(dump_data->nentries + 1,
+			       sizeof(*ramdump_segs),
+			       GFP_KERNEL);
+	if (!ramdump_segs)
+		return -ENOMEM;
+
+	s = ramdump_segs + 1;
+	for (i = 0; i < dump_data->nentries; i++) {
+		if (dump_seg->type >= CNSS_FW_DUMP_TYPE_MAX) {
+			cnss_pr_err("Unsupported dump type: %d",
+				    dump_seg->type);
+			continue;
+		}
+
+		if (meta_info.entry[dump_seg->type].entry_start == 0) {
+			meta_info.entry[dump_seg->type].type = dump_seg->type;
+			meta_info.entry[dump_seg->type].entry_start = i + 1;
+		}
+		meta_info.entry[dump_seg->type].entry_num++;
+
+		s->address = dump_seg->address;
+		s->v_address = (void __iomem *)dump_seg->v_address;
+		s->size = dump_seg->size;
+		s++;
+		dump_seg++;
+	}
+
+	meta_info.magic = CNSS_RAMDUMP_MAGIC;
+	meta_info.version = CNSS_RAMDUMP_VERSION;
+	meta_info.chipset = plat_priv->device_id;
+	meta_info.total_entries = CNSS_FW_DUMP_TYPE_MAX;
+
+	ramdump_segs->v_address = (void __iomem *)(&meta_info);
+	ramdump_segs->size = sizeof(meta_info);
+
+	ret = qcom_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
+			       dump_data->nentries + 1);
+	kfree(ramdump_segs);
+
+	return ret;
+}
+#else
+static int cnss_panic_handler(struct notifier_block *nb, unsigned long action,
+			      void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(nb, struct cnss_plat_data, panic_nb);
+
+	cnss_bus_dev_crash_shutdown(plat_priv);
+
+	return NOTIFY_DONE;
+}
+
+int cnss_register_subsys(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	plat_priv->panic_nb.notifier_call = cnss_panic_handler;
+	ret = atomic_notifier_chain_register(&panic_notifier_list,
+					     &plat_priv->panic_nb);
+	if (ret) {
+		cnss_pr_err("Failed to register panic handler\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	ret = atomic_notifier_chain_unregister(&panic_notifier_list,
+					       &plat_priv->panic_nb);
+	if (ret)
+		cnss_pr_err("Failed to unregister panic handler\n");
+}
+
+#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2)
+static void *cnss_create_ramdump_device(struct cnss_plat_data *plat_priv)
+{
+	return &plat_priv->plat_dev->dev;
+}
+
+static void cnss_destroy_ramdump_device(struct cnss_plat_data *plat_priv,
+					void *ramdump_dev)
+{
+}
+#endif
+
+#if IS_ENABLED(CONFIG_QCOM_RAMDUMP)
+int cnss_do_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info *ramdump_info = &plat_priv->ramdump_info;
+	struct qcom_dump_segment segment;
+	struct list_head head;
+
+	if (!dump_enabled()) {
+		cnss_pr_info("Dump collection is not enabled\n");
+		return 0;
+	}
+	INIT_LIST_HEAD(&head);
+	memset(&segment, 0, sizeof(segment));
+	segment.va = ramdump_info->ramdump_va;
+	segment.size = ramdump_info->ramdump_size;
+	list_add(&segment.node, &head);
+
+	return qcom_dump(&head, ramdump_info->ramdump_dev);
+}
+#else
+int cnss_do_ramdump(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+/* Using completion event inside dynamically allocated ramdump_desc
+ * may result a race between freeing the event after setting it to
+ * complete inside dev coredump free callback and the thread that is
+ * waiting for completion.
+ */
+DECLARE_COMPLETION(dump_done);
+#define TIMEOUT_SAVE_DUMP_MS 30000
+
+#define SIZEOF_ELF_STRUCT(__xhdr)					\
+static inline size_t sizeof_elf_##__xhdr(unsigned char class)		\
+{									\
+	if (class == ELFCLASS32)					\
+		return sizeof(struct elf32_##__xhdr);			\
+	else								\
+		return sizeof(struct elf64_##__xhdr);			\
+}
+
+SIZEOF_ELF_STRUCT(phdr)
+SIZEOF_ELF_STRUCT(hdr)
+
+#define set_xhdr_property(__xhdr, arg, class, member, value)		\
+do {									\
+	if (class == ELFCLASS32)					\
+		((struct elf32_##__xhdr *)arg)->member = value;		\
+	else								\
+		((struct elf64_##__xhdr *)arg)->member = value;		\
+} while (0)
+
+#define set_ehdr_property(arg, class, member, value) \
+	set_xhdr_property(hdr, arg, class, member, value)
+#define set_phdr_property(arg, class, member, value) \
+	set_xhdr_property(phdr, arg, class, member, value)
+
+/* These replace qcom_ramdump driver APIs called from common API
+ * cnss_do_elf_dump() by the ones defined here.
+ */
+#define qcom_dump_segment cnss_qcom_dump_segment
+#define qcom_elf_dump cnss_qcom_elf_dump
+#define dump_enabled cnss_dump_enabled
+
+struct cnss_qcom_dump_segment {
+	struct list_head node;
+	dma_addr_t da;
+	void *va;
+	size_t size;
+};
+
+struct cnss_qcom_ramdump_desc {
+	void *data;
+	struct completion dump_done;
+};
+
+static ssize_t cnss_qcom_devcd_readv(char *buffer, loff_t offset, size_t count,
+				     void *data, size_t datalen)
+{
+	struct cnss_qcom_ramdump_desc *desc = data;
+
+	return memory_read_from_buffer(buffer, count, &offset, desc->data,
+				       datalen);
+}
+
+static void cnss_qcom_devcd_freev(void *data)
+{
+	struct cnss_qcom_ramdump_desc *desc = data;
+
+	cnss_pr_dbg("Free dump data for dev coredump\n");
+
+	complete(&dump_done);
+	vfree(desc->data);
+	kfree(desc);
+}
+
+static int cnss_qcom_devcd_dump(struct device *dev, void *data, size_t datalen,
+				gfp_t gfp)
+{
+	struct cnss_qcom_ramdump_desc *desc;
+	unsigned int timeout = TIMEOUT_SAVE_DUMP_MS;
+	int ret;
+
+	desc = kmalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->data = data;
+	reinit_completion(&dump_done);
+
+	dev_coredumpm(dev, NULL, desc, datalen, gfp,
+		      cnss_qcom_devcd_readv, cnss_qcom_devcd_freev);
+
+	ret = wait_for_completion_timeout(&dump_done,
+					  msecs_to_jiffies(timeout));
+	if (!ret)
+		cnss_pr_err("Timeout waiting (%dms) for saving dump to file system\n",
+			    timeout);
+
+	return ret ? 0 : -ETIMEDOUT;
+}
+
+/* Since the elf32 and elf64 identification is identical apart from
+ * the class, use elf32 by default.
+ */
+static void init_elf_identification(struct elf32_hdr *ehdr, unsigned char class)
+{
+	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = class;
+	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+}
+
+static int cnss_qcom_elf_dump(struct list_head *segs, struct device *dev,
+			      unsigned char class)
+{
+	struct cnss_qcom_dump_segment *segment;
+	void *phdr, *ehdr;
+	size_t data_size, offset;
+	int phnum = 0;
+	void *data;
+	void __iomem *ptr;
+
+	if (!segs || list_empty(segs))
+		return -EINVAL;
+
+	data_size = sizeof_elf_hdr(class);
+	list_for_each_entry(segment, segs, node) {
+		data_size += sizeof_elf_phdr(class) + segment->size;
+		phnum++;
+	}
+
+	data = vmalloc(data_size);
+	if (!data)
+		return -ENOMEM;
+
+	cnss_pr_dbg("Creating ELF file with size %d\n", data_size);
+
+	ehdr = data;
+	memset(ehdr, 0, sizeof_elf_hdr(class));
+	init_elf_identification(ehdr, class);
+	set_ehdr_property(ehdr, class, e_type, ET_CORE);
+	set_ehdr_property(ehdr, class, e_machine, EM_NONE);
+	set_ehdr_property(ehdr, class, e_version, EV_CURRENT);
+	set_ehdr_property(ehdr, class, e_phoff, sizeof_elf_hdr(class));
+	set_ehdr_property(ehdr, class, e_ehsize, sizeof_elf_hdr(class));
+	set_ehdr_property(ehdr, class, e_phentsize, sizeof_elf_phdr(class));
+	set_ehdr_property(ehdr, class, e_phnum, phnum);
+
+	phdr = data + sizeof_elf_hdr(class);
+	offset = sizeof_elf_hdr(class) + sizeof_elf_phdr(class) * phnum;
+	list_for_each_entry(segment, segs, node) {
+		memset(phdr, 0, sizeof_elf_phdr(class));
+		set_phdr_property(phdr, class, p_type, PT_LOAD);
+		set_phdr_property(phdr, class, p_offset, offset);
+		set_phdr_property(phdr, class, p_vaddr, segment->da);
+		set_phdr_property(phdr, class, p_paddr, segment->da);
+		set_phdr_property(phdr, class, p_filesz, segment->size);
+		set_phdr_property(phdr, class, p_memsz, segment->size);
+		set_phdr_property(phdr, class, p_flags, PF_R | PF_W | PF_X);
+		set_phdr_property(phdr, class, p_align, 0);
+
+		if (segment->va) {
+			memcpy(data + offset, segment->va, segment->size);
+		} else {
+			ptr = devm_ioremap(dev, segment->da, segment->size);
+			if (!ptr) {
+				cnss_pr_err("Invalid coredump segment (%pad, %zu)\n",
+					    &segment->da, segment->size);
+				memset(data + offset, 0xff, segment->size);
+			} else {
+				memcpy_fromio(data + offset, ptr,
+					      segment->size);
+			}
+		}
+
+		offset += segment->size;
+		phdr += sizeof_elf_phdr(class);
+	}
+
+	return cnss_qcom_devcd_dump(dev, data, data_size, GFP_KERNEL);
+}
+
+/* Saving dump to file system is always needed in this case. */
+static bool cnss_dump_enabled(void)
+{
+	return true;
+}
+#endif /* CONFIG_QCOM_RAMDUMP */
+
+int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+	struct cnss_dump_data *dump_data = &info_v2->dump_data;
+	struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+	struct qcom_dump_segment *seg;
+	struct cnss_dump_meta_info meta_info = {0};
+	struct list_head head;
+	int i, ret = 0;
+
+	if (!dump_enabled()) {
+		cnss_pr_info("Dump collection is not enabled\n");
+		return ret;
+	}
+
+	INIT_LIST_HEAD(&head);
+	for (i = 0; i < dump_data->nentries; i++) {
+		if (dump_seg->type >= CNSS_FW_DUMP_TYPE_MAX) {
+			cnss_pr_err("Unsupported dump type: %d",
+				    dump_seg->type);
+			continue;
+		}
+
+		seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
+		if (!seg) {
+			cnss_pr_err("%s: Failed to allocate mem for seg %d\n",
+				    __func__, i);
+			continue;
+		}
+
+		if (meta_info.entry[dump_seg->type].entry_start == 0) {
+			meta_info.entry[dump_seg->type].type = dump_seg->type;
+			meta_info.entry[dump_seg->type].entry_start = i + 1;
+		}
+		meta_info.entry[dump_seg->type].entry_num++;
+		seg->da = dump_seg->address;
+		seg->va = dump_seg->v_address;
+		seg->size = dump_seg->size;
+		list_add_tail(&seg->node, &head);
+		dump_seg++;
+	}
+
+	seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
+	if (!seg) {
+		cnss_pr_err("%s: Failed to allocate mem for elf ramdump seg\n",
+			    __func__);
+		goto skip_elf_dump;
+	}
+
+	meta_info.magic = CNSS_RAMDUMP_MAGIC;
+	meta_info.version = CNSS_RAMDUMP_VERSION;
+	meta_info.chipset = plat_priv->device_id;
+	meta_info.total_entries = CNSS_FW_DUMP_TYPE_MAX;
+	seg->va = &meta_info;
+	seg->size = sizeof(meta_info);
+	list_add(&seg->node, &head);
+
+	ret = qcom_elf_dump(&head, info_v2->ramdump_dev, ELF_CLASS);
+
+skip_elf_dump:
+	while (!list_empty(&head)) {
+		seg = list_first_entry(&head, struct qcom_dump_segment, node);
+		list_del(&seg->node);
+		kfree(seg);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
+/**
+ * cnss_host_ramdump_dev_release() - callback function for device release
+ * @dev: device to be released
+ *
+ * Return: None
+ */
+static void cnss_host_ramdump_dev_release(struct device *dev)
+{
+	cnss_pr_dbg("free host ramdump device\n");
+	kfree(dev);
+}
+
+int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
+			 struct cnss_ssr_driver_dump_entry *ssr_entry,
+			 size_t num_entries_loaded)
+{
+	struct qcom_dump_segment *seg;
+	struct cnss_host_dump_meta_info meta_info = {0};
+	struct list_head head;
+	int dev_ret = 0;
+	struct device *new_device;
+	static const char * const wlan_str[] = {
+		[CNSS_HOST_WLAN_LOGS] = "wlan_logs",
+		[CNSS_HOST_HTC_CREDIT] = "htc_credit",
+		[CNSS_HOST_WMI_TX_CMP] = "wmi_tx_cmp",
+		[CNSS_HOST_WMI_COMMAND_LOG] = "wmi_command_log",
+		[CNSS_HOST_WMI_EVENT_LOG] = "wmi_event_log",
+		[CNSS_HOST_WMI_RX_EVENT] = "wmi_rx_event",
+		[CNSS_HOST_HAL_SOC] = "hal_soc",
+		[CNSS_HOST_GWLAN_LOGGING] = "gwlan_logging",
+		[CNSS_HOST_WMI_DEBUG_LOG_INFO] = "wmi_debug_log_info",
+		[CNSS_HOST_HTC_CREDIT_IDX] = "htc_credit_history_idx",
+		[CNSS_HOST_HTC_CREDIT_LEN] = "htc_credit_history_length",
+		[CNSS_HOST_WMI_TX_CMP_IDX] = "wmi_tx_cmp_idx",
+		[CNSS_HOST_WMI_COMMAND_LOG_IDX] = "wmi_command_log_idx",
+		[CNSS_HOST_WMI_EVENT_LOG_IDX] = "wmi_event_log_idx",
+		[CNSS_HOST_WMI_RX_EVENT_IDX] = "wmi_rx_event_idx",
+		[CNSS_HOST_HIF_CE_DESC_HISTORY_BUFF] = "hif_ce_desc_history_buff",
+		[CNSS_HOST_HANG_EVENT_DATA] = "hang_event_data",
+		[CNSS_HOST_CE_DESC_HIST] = "hif_ce_desc_hist",
+		[CNSS_HOST_CE_COUNT_MAX] = "hif_ce_count_max",
+		[CNSS_HOST_CE_HISTORY_MAX] = "hif_ce_history_max",
+		[CNSS_HOST_ONLY_FOR_CRIT_CE] = "hif_ce_only_for_crit",
+		[CNSS_HOST_HIF_EVENT_HISTORY] = "hif_event_history",
+		[CNSS_HOST_HIF_EVENT_HIST_MAX] = "hif_event_hist_max",
+		[CNSS_HOST_DP_WBM_DESC_REL] = "wbm_desc_rel_ring",
+		[CNSS_HOST_DP_WBM_DESC_REL_HANDLE] = "wbm_desc_rel_ring_handle",
+		[CNSS_HOST_DP_TCL_CMD] = "tcl_cmd_ring",
+		[CNSS_HOST_DP_TCL_CMD_HANDLE] = "tcl_cmd_ring_handle",
+		[CNSS_HOST_DP_TCL_STATUS] = "tcl_status_ring",
+		[CNSS_HOST_DP_TCL_STATUS_HANDLE] = "tcl_status_ring_handle",
+		[CNSS_HOST_DP_REO_REINJ] = "reo_reinject_ring",
+		[CNSS_HOST_DP_REO_REINJ_HANDLE] = "reo_reinject_ring_handle",
+		[CNSS_HOST_DP_RX_REL] = "rx_rel_ring",
+		[CNSS_HOST_DP_RX_REL_HANDLE] = "rx_rel_ring_handle",
+		[CNSS_HOST_DP_REO_EXP] = "reo_exception_ring",
+		[CNSS_HOST_DP_REO_EXP_HANDLE] = "reo_exception_ring_handle",
+		[CNSS_HOST_DP_REO_CMD] = "reo_cmd_ring",
+		[CNSS_HOST_DP_REO_CMD_HANDLE] = "reo_cmd_ring_handle",
+		[CNSS_HOST_DP_REO_STATUS] = "reo_status_ring",
+		[CNSS_HOST_DP_REO_STATUS_HANDLE] = "reo_status_ring_handle",
+		[CNSS_HOST_DP_TCL_DATA_0] = "tcl_data_ring_0",
+		[CNSS_HOST_DP_TCL_DATA_0_HANDLE] = "tcl_data_ring_0_handle",
+		[CNSS_HOST_DP_TX_COMP_0] = "tx_comp_ring_0",
+		[CNSS_HOST_DP_TX_COMP_0_HANDLE] = "tx_comp_ring_0_handle",
+		[CNSS_HOST_DP_TCL_DATA_1] = "tcl_data_ring_1",
+		[CNSS_HOST_DP_TCL_DATA_1_HANDLE] = "tcl_data_ring_1_handle",
+		[CNSS_HOST_DP_TX_COMP_1] = "tx_comp_ring_1",
+		[CNSS_HOST_DP_TX_COMP_1_HANDLE] = "tx_comp_ring_1_handle",
+		[CNSS_HOST_DP_TCL_DATA_2] = "tcl_data_ring_2",
+		[CNSS_HOST_DP_TCL_DATA_2_HANDLE] = "tcl_data_ring_2_handle",
+		[CNSS_HOST_DP_TX_COMP_2] = "tx_comp_ring_2",
+		[CNSS_HOST_DP_TX_COMP_2_HANDLE] = "tx_comp_ring_2_handle",
+		[CNSS_HOST_DP_REO_DST_0] = "reo_dest_ring_0",
+		[CNSS_HOST_DP_REO_DST_0_HANDLE] = "reo_dest_ring_0_handle",
+		[CNSS_HOST_DP_REO_DST_1] = "reo_dest_ring_1",
+		[CNSS_HOST_DP_REO_DST_1_HANDLE] = "reo_dest_ring_1_handle",
+		[CNSS_HOST_DP_REO_DST_2] = "reo_dest_ring_2",
+		[CNSS_HOST_DP_REO_DST_2_HANDLE] = "reo_dest_ring_2_handle",
+		[CNSS_HOST_DP_REO_DST_3] = "reo_dest_ring_3",
+		[CNSS_HOST_DP_REO_DST_3_HANDLE] = "reo_dest_ring_3_handle",
+		[CNSS_HOST_DP_REO_DST_4] = "reo_dest_ring_4",
+		[CNSS_HOST_DP_REO_DST_4_HANDLE] = "reo_dest_ring_4_handle",
+		[CNSS_HOST_DP_REO_DST_5] = "reo_dest_ring_5",
+		[CNSS_HOST_DP_REO_DST_5_HANDLE] = "reo_dest_ring_5_handle",
+		[CNSS_HOST_DP_REO_DST_6] = "reo_dest_ring_6",
+		[CNSS_HOST_DP_REO_DST_6_HANDLE] = "reo_dest_ring_6_handle",
+		[CNSS_HOST_DP_REO_DST_7] = "reo_dest_ring_7",
+		[CNSS_HOST_DP_REO_DST_7_HANDLE] = "reo_dest_ring_7_handle",
+		[CNSS_HOST_DP_PDEV_0] = "dp_pdev_0",
+		[CNSS_HOST_DP_WLAN_CFG_CTX] = "wlan_cfg_ctx",
+		[CNSS_HOST_DP_SOC] = "dp_soc",
+		[CNSS_HOST_HAL_RX_FST] = "hal_rx_fst",
+		[CNSS_HOST_DP_FISA] = "dp_fisa",
+		[CNSS_HOST_DP_FISA_HW_FSE_TABLE] = "dp_fisa_hw_fse_table",
+		[CNSS_HOST_DP_FISA_SW_FSE_TABLE] = "dp_fisa_sw_fse_table",
+		[CNSS_HOST_HIF] = "hif",
+		[CNSS_HOST_QDF_NBUF_HIST] = "qdf_nbuf_history",
+		[CNSS_HOST_TCL_WBM_MAP] = "tcl_wbm_map_array",
+		[CNSS_HOST_RX_MAC_BUF_RING_0] = "rx_mac_buf_ring_0",
+		[CNSS_HOST_RX_MAC_BUF_RING_0_HANDLE] = "rx_mac_buf_ring_0_handle",
+		[CNSS_HOST_RX_MAC_BUF_RING_1] = "rx_mac_buf_ring_1",
+		[CNSS_HOST_RX_MAC_BUF_RING_1_HANDLE] = "rx_mac_buf_ring_1_handle",
+		[CNSS_HOST_RX_REFILL_0] = "rx_refill_buf_ring_0",
+		[CNSS_HOST_RX_REFILL_0_HANDLE] = "rx_refill_buf_ring_0_handle",
+		[CNSS_HOST_CE_0] = "ce_0",
+		[CNSS_HOST_CE_0_SRC_RING] = "ce_0_src_ring",
+		[CNSS_HOST_CE_0_SRC_RING_CTX] = "ce_0_src_ring_ctx",
+		[CNSS_HOST_CE_1] = "ce_1",
+		[CNSS_HOST_CE_1_STATUS_RING] = "ce_1_status_ring",
+		[CNSS_HOST_CE_1_STATUS_RING_CTX] = "ce_1_status_ring_ctx",
+		[CNSS_HOST_CE_1_DEST_RING] = "ce_1_dest_ring",
+		[CNSS_HOST_CE_1_DEST_RING_CTX] = "ce_1_dest_ring_ctx",
+		[CNSS_HOST_CE_2] = "ce_2",
+		[CNSS_HOST_CE_2_STATUS_RING] = "ce_2_status_ring",
+		[CNSS_HOST_CE_2_STATUS_RING_CTX] = "ce_2_status_ring_ctx",
+		[CNSS_HOST_CE_2_DEST_RING] = "ce_2_dest_ring",
+		[CNSS_HOST_CE_2_DEST_RING_CTX] = "ce_2_dest_ring_ctx",
+		[CNSS_HOST_CE_3] = "ce_3",
+		[CNSS_HOST_CE_3_SRC_RING] = "ce_3_src_ring",
+		[CNSS_HOST_CE_3_SRC_RING_CTX] = "ce_3_src_ring_ctx",
+		[CNSS_HOST_CE_4] = "ce_4",
+		[CNSS_HOST_CE_4_SRC_RING] = "ce_4_src_ring",
+		[CNSS_HOST_CE_4_SRC_RING_CTX] = "ce_4_src_ring_ctx",
+		[CNSS_HOST_CE_5] = "ce_5",
+		[CNSS_HOST_CE_6] = "ce_6",
+		[CNSS_HOST_CE_7] = "ce_7",
+		[CNSS_HOST_CE_7_STATUS_RING] = "ce_7_status_ring",
+		[CNSS_HOST_CE_7_STATUS_RING_CTX] = "ce_7_status_ring_ctx",
+		[CNSS_HOST_CE_7_DEST_RING] = "ce_7_dest_ring",
+		[CNSS_HOST_CE_7_DEST_RING_CTX] = "ce_7_dest_ring_ctx",
+		[CNSS_HOST_CE_8] = "ce_8",
+		[CNSS_HOST_DP_TCL_DATA_3] = "tcl_data_ring_3",
+		[CNSS_HOST_DP_TCL_DATA_3_HANDLE] = "tcl_data_ring_3_handle",
+		[CNSS_HOST_DP_TX_COMP_3] = "tx_comp_ring_3",
+		[CNSS_HOST_DP_TX_COMP_3_HANDLE] = "tx_comp_ring_3_handle"
+	};
+	int i;
+	int ret = 0;
+	enum cnss_host_dump_type j;
+
+	if (!dump_enabled()) {
+		cnss_pr_info("Dump collection is not enabled\n");
+		return ret;
+	}
+
+	new_device = kcalloc(1, sizeof(*new_device), GFP_KERNEL);
+	if (!new_device) {
+		cnss_pr_err("Failed to alloc device mem\n");
+		return -ENOMEM;
+	}
+
+	new_device->release = cnss_host_ramdump_dev_release;
+	device_initialize(new_device);
+	dev_set_name(new_device, "wlan_driver");
+	dev_ret = device_add(new_device);
+	if (dev_ret) {
+		cnss_pr_err("Failed to add new device\n");
+		goto put_device;
+	}
+
+	INIT_LIST_HEAD(&head);
+	for (i = 0; i < num_entries_loaded; i++) {
+		/* If region name registered by driver is not present in
+		 * wlan_str. type for that entry will not be set, but entry will
+		 * be added. Which will result in entry type being 0. Currently
+		 * entry type 0 is for wlan_logs, which will result in parsing
+		 * issue for wlan_logs as parsing is done based upon type field.
+		 * So initialize type with -1(Invalid) to avoid such issues.
+		 */
+		meta_info.entry[i].type = -1;
+		seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
+		if (!seg) {
+			cnss_pr_err("Failed to alloc seg entry %d\n", i);
+			continue;
+		}
+
+		seg->va = ssr_entry[i].buffer_pointer;
+		seg->da = (dma_addr_t)ssr_entry[i].buffer_pointer;
+		seg->size = ssr_entry[i].buffer_size;
+
+		for (j = 0; j < CNSS_HOST_DUMP_TYPE_MAX; j++) {
+			if (strcmp(ssr_entry[i].region_name, wlan_str[j]) == 0) {
+				meta_info.entry[i].type = j;
+			}
+		}
+		meta_info.entry[i].entry_start = i + 1;
+		meta_info.entry[i].entry_num++;
+
+		list_add_tail(&seg->node, &head);
+	}
+
+	seg = kcalloc(1, sizeof(*seg), GFP_KERNEL);
+
+	if (!seg) {
+		cnss_pr_err("%s: Failed to allocate mem for host dump seg\n",
+			    __func__);
+		goto skip_host_dump;
+	}
+
+	meta_info.magic = CNSS_RAMDUMP_MAGIC;
+	meta_info.version = CNSS_RAMDUMP_VERSION;
+	meta_info.chipset = plat_priv->device_id;
+	meta_info.total_entries = num_entries_loaded;
+	seg->va = &meta_info;
+	seg->da = (dma_addr_t)&meta_info;
+	seg->size = sizeof(meta_info);
+	list_add(&seg->node, &head);
+
+	ret = qcom_elf_dump(&head, new_device, ELF_CLASS);
+
+skip_host_dump:
+	while (!list_empty(&head)) {
+		seg = list_first_entry(&head, struct qcom_dump_segment, node);
+		list_del(&seg->node);
+		kfree(seg);
+	}
+	device_del(new_device);
+put_device:
+	put_device(new_device);
+	cnss_pr_dbg("host ramdump result %d\n", ret);
+	return ret;
+}
+#endif
+#endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
+
+#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2)
+static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info *ramdump_info;
+	struct msm_dump_entry dump_entry;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	ramdump_info->dump_data.addr = ramdump_info->ramdump_pa;
+	ramdump_info->dump_data.len = ramdump_info->ramdump_size;
+	ramdump_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(ramdump_info->dump_data.name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&ramdump_info->dump_data);
+
+	return msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS,
+						&dump_entry);
+}
+
+static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_ramdump_info *ramdump_info;
+	u32 ramdump_size = 0;
+
+	dev = &plat_priv->plat_dev->dev;
+	ramdump_info = &plat_priv->ramdump_info;
+
+	if (plat_priv->dt_type != CNSS_DTT_MULTIEXCHG) {
+		/* dt type: legacy or converged */
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,wlan-ramdump-dynamic",
+					   &ramdump_size);
+	} else {
+		ret = of_property_read_u32(plat_priv->dev_node,
+					   "qcom,wlan-ramdump-dynamic",
+					   &ramdump_size);
+	}
+	if (ret == 0) {
+		ramdump_info->ramdump_va =
+			dma_alloc_coherent(dev, ramdump_size,
+					   &ramdump_info->ramdump_pa,
+					   GFP_KERNEL);
+
+		if (ramdump_info->ramdump_va)
+			ramdump_info->ramdump_size = ramdump_size;
+	}
+
+	cnss_pr_dbg("ramdump va: %pK, pa: %pa\n",
+		    ramdump_info->ramdump_va, &ramdump_info->ramdump_pa);
+
+	if (ramdump_info->ramdump_size == 0) {
+		cnss_pr_info("Ramdump will not be collected");
+		goto out;
+	}
+
+	ret = cnss_init_dump_entry(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
+		goto free_ramdump;
+	}
+
+	ramdump_info->ramdump_dev = cnss_create_ramdump_device(plat_priv);
+	if (!ramdump_info->ramdump_dev) {
+		cnss_pr_err("Failed to create ramdump device!");
+		ret = -ENOMEM;
+		goto free_ramdump;
+	}
+
+	return 0;
+free_ramdump:
+	dma_free_coherent(dev, ramdump_info->ramdump_size,
+			  ramdump_info->ramdump_va, ramdump_info->ramdump_pa);
+out:
+	return ret;
+}
+
+static void cnss_unregister_ramdump_v1(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct cnss_ramdump_info *ramdump_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	ramdump_info = &plat_priv->ramdump_info;
+
+	if (ramdump_info->ramdump_dev)
+		cnss_destroy_ramdump_device(plat_priv,
+					    ramdump_info->ramdump_dev);
+
+	if (ramdump_info->ramdump_va)
+		dma_free_coherent(dev, ramdump_info->ramdump_size,
+				  ramdump_info->ramdump_va,
+				  ramdump_info->ramdump_pa);
+}
+
+/**
+ * cnss_ignore_dump_data_reg_fail - Ignore Ramdump table register failure
+ * @ret: Error returned by msm_dump_data_register_nominidump
+ *
+ * For Lahaina GKI boot, we dont have support for mem dump feature. So
+ * ignore failure.
+ *
+ * Return: Same given error code if mem dump feature enabled, 0 otherwise
+ */
+static int cnss_ignore_dump_data_reg_fail(int ret)
+{
+	return ret;
+}
+
+static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_ramdump_info_v2 *info_v2;
+	struct cnss_dump_data *dump_data;
+	struct msm_dump_entry dump_entry;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	u32 ramdump_size = 0;
+
+	info_v2 = &plat_priv->ramdump_info_v2;
+	dump_data = &info_v2->dump_data;
+
+	if (plat_priv->dt_type != CNSS_DTT_MULTIEXCHG) {
+		/* dt type: legacy or converged */
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,wlan-ramdump-dynamic",
+					   &ramdump_size);
+	} else {
+		ret = of_property_read_u32(plat_priv->dev_node,
+					   "qcom,wlan-ramdump-dynamic",
+					   &ramdump_size);
+	}
+	if (ret == 0)
+		info_v2->ramdump_size = ramdump_size;
+
+	cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
+
+	info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
+	if (!info_v2->dump_data_vaddr)
+		return -ENOMEM;
+
+	dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
+	dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
+	dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
+	dump_data->seg_version = CNSS_DUMP_SEG_VER;
+	strlcpy(dump_data->name, CNSS_DUMP_NAME,
+		sizeof(dump_data->name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(dump_data);
+
+	ret = msm_dump_data_register_nominidump(MSM_DUMP_TABLE_APPS,
+						&dump_entry);
+	if (ret) {
+		ret = cnss_ignore_dump_data_reg_fail(ret);
+		cnss_pr_err("Failed to setup dump table, %s (%d)\n",
+			    ret ? "Error" : "Ignoring", ret);
+		goto free_ramdump;
+	}
+
+	info_v2->ramdump_dev = cnss_create_ramdump_device(plat_priv);
+	if (!info_v2->ramdump_dev) {
+		cnss_pr_err("Failed to create ramdump device!\n");
+		ret = -ENOMEM;
+		goto free_ramdump;
+	}
+
+	return 0;
+
+free_ramdump:
+	kfree(info_v2->dump_data_vaddr);
+	info_v2->dump_data_vaddr = NULL;
+	return ret;
+}
+
+static void cnss_unregister_ramdump_v2(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2;
+
+	info_v2 = &plat_priv->ramdump_info_v2;
+
+	if (info_v2->ramdump_dev)
+		cnss_destroy_ramdump_device(plat_priv, info_v2->ramdump_dev);
+
+	kfree(info_v2->dump_data_vaddr);
+	info_v2->dump_data_vaddr = NULL;
+	info_v2->dump_data_valid = false;
+}
+
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_register_ramdump_v1(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:
+	case PEACH_DEVICE_ID:
+		ret = cnss_register_ramdump_v2(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+		ret = -ENODEV;
+		break;
+	}
+	return ret;
+}
+
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		cnss_unregister_ramdump_v1(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:
+	case PEACH_DEVICE_ID:
+		cnss_unregister_ramdump_v2(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+		break;
+	}
+}
+#else
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+	struct cnss_dump_data *dump_data = dump_data = &info_v2->dump_data;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	u32 ramdump_size = 0;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0)
+		info_v2->ramdump_size = ramdump_size;
+
+	cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
+
+	info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
+	if (!info_v2->dump_data_vaddr)
+		return -ENOMEM;
+
+	dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
+	dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
+	dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
+	dump_data->seg_version = CNSS_DUMP_SEG_VER;
+	strlcpy(dump_data->name, CNSS_DUMP_NAME,
+		sizeof(dump_data->name));
+
+	info_v2->ramdump_dev = dev;
+
+	return 0;
+}
+
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+
+	info_v2->ramdump_dev = NULL;
+	kfree(info_v2->dump_data_vaddr);
+	info_v2->dump_data_vaddr = NULL;
+	info_v2->dump_data_valid = false;
+}
+#endif /* CONFIG_QCOM_MEMORY_DUMP_V2 */
+
+int cnss_va_to_pa(struct device *dev, size_t size, void *va, dma_addr_t dma,
+		  phys_addr_t *pa, unsigned long attrs)
+{
+	struct sg_table sgt;
+	int ret;
+
+	ret = dma_get_sgtable_attrs(dev, &sgt, va, dma, size, attrs);
+	if (ret) {
+		cnss_pr_err("Failed to get sgtable for va: 0x%pK, dma: %pa, size: 0x%zx, attrs: 0x%x\n",
+			    va, &dma, size, attrs);
+		return -EINVAL;
+	}
+
+	*pa = page_to_phys(sg_page(sgt.sgl));
+	sg_free_table(&sgt);
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_QCOM_MINIDUMP)
+int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
+			     enum cnss_fw_dump_type type, int seg_no,
+			     void *va, phys_addr_t pa, size_t size)
+{
+	struct md_region md_entry;
+	int ret;
+
+	switch (type) {
+	case CNSS_FW_IMAGE:
+		snprintf(md_entry.name, sizeof(md_entry.name), "FBC_%X",
+			 seg_no);
+		break;
+	case CNSS_FW_RDDM:
+		snprintf(md_entry.name, sizeof(md_entry.name), "RDDM_%X",
+			 seg_no);
+		break;
+	case CNSS_FW_REMOTE_HEAP:
+		snprintf(md_entry.name, sizeof(md_entry.name), "RHEAP_%X",
+			 seg_no);
+		break;
+	default:
+		cnss_pr_err("Unknown dump type ID: %d\n", type);
+		return -EINVAL;
+	}
+
+	md_entry.phys_addr = pa;
+	md_entry.virt_addr = (uintptr_t)va;
+	md_entry.size = size;
+	md_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+
+	cnss_pr_dbg("Mini dump region: %s, va: %pK, pa: %pa, size: 0x%zx\n",
+		    md_entry.name, va, &pa, size);
+
+	ret = msm_minidump_add_region(&md_entry);
+	if (ret < 0)
+		cnss_pr_err("Failed to add mini dump region, err = %d\n", ret);
+
+	return ret;
+}
+
+int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv,
+				enum cnss_fw_dump_type type, int seg_no,
+				void *va, phys_addr_t pa, size_t size)
+{
+	struct md_region md_entry;
+	int ret;
+
+	switch (type) {
+	case CNSS_FW_IMAGE:
+		snprintf(md_entry.name, sizeof(md_entry.name), "FBC_%X",
+			 seg_no);
+		break;
+	case CNSS_FW_RDDM:
+		snprintf(md_entry.name, sizeof(md_entry.name), "RDDM_%X",
+			 seg_no);
+		break;
+	case CNSS_FW_REMOTE_HEAP:
+		snprintf(md_entry.name, sizeof(md_entry.name), "RHEAP_%X",
+			 seg_no);
+		break;
+	default:
+		cnss_pr_err("Unknown dump type ID: %d\n", type);
+		return -EINVAL;
+	}
+
+	md_entry.phys_addr = pa;
+	md_entry.virt_addr = (uintptr_t)va;
+	md_entry.size = size;
+	md_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+
+	cnss_pr_vdbg("Remove mini dump region: %s, va: %pK, pa: %pa, size: 0x%zx\n",
+		     md_entry.name, va, &pa, size);
+
+	ret = msm_minidump_remove_region(&md_entry);
+	if (ret)
+		cnss_pr_err("Failed to remove mini dump region, err = %d\n",
+			    ret);
+
+	return ret;
+}
+#else
+int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
+			     enum cnss_fw_dump_type type, int seg_no,
+			     void *va, phys_addr_t pa, size_t size)
+{
+	char name[MAX_NAME_LEN];
+
+	switch (type) {
+	case CNSS_FW_IMAGE:
+		snprintf(name, MAX_NAME_LEN, "FBC_%X", seg_no);
+		break;
+	case CNSS_FW_RDDM:
+		snprintf(name, MAX_NAME_LEN, "RDDM_%X", seg_no);
+		break;
+	case CNSS_FW_REMOTE_HEAP:
+		snprintf(name, MAX_NAME_LEN, "RHEAP_%X", seg_no);
+		break;
+	default:
+		cnss_pr_err("Unknown dump type ID: %d\n", type);
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Dump region: %s, va: %pK, pa: %pa, size: 0x%zx\n",
+		    name, va, &pa, size);
+	return 0;
+}
+
+int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv,
+				enum cnss_fw_dump_type type, int seg_no,
+				void *va, phys_addr_t pa, size_t size)
+{
+	return 0;
+}
+#endif /* CONFIG_QCOM_MINIDUMP */
+
+int cnss_request_firmware_direct(struct cnss_plat_data *plat_priv,
+				 const struct firmware **fw_entry,
+				 const char *filename)
+{
+	if (IS_ENABLED(CONFIG_CNSS_REQ_FW_DIRECT))
+		return request_firmware_direct(fw_entry, filename,
+					       &plat_priv->plat_dev->dev);
+	else
+		return firmware_request_nowarn(fw_entry, filename,
+					       &plat_priv->plat_dev->dev);
+}
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+/**
+ * cnss_register_bus_scale() - Setup interconnect voting data
+ * @plat_priv: Platform data structure
+ *
+ * For different interconnect path configured in device tree setup voting data
+ * for list of bandwidth requirements.
+ *
+ * Result: 0 for success. -EINVAL if not configured
+ */
+static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
+{
+	int ret = -EINVAL;
+	u32 idx, i, j, cfg_arr_size, *cfg_arr = NULL;
+	struct cnss_bus_bw_info *bus_bw_info, *tmp;
+	struct device *dev = &plat_priv->plat_dev->dev;
+
+	INIT_LIST_HEAD(&plat_priv->icc.list_head);
+	ret = of_property_read_u32(dev->of_node,
+				   "qcom,icc-path-count",
+				   &plat_priv->icc.path_count);
+	if (ret) {
+		cnss_pr_dbg("Platform Bus Interconnect path not configured\n");
+		return 0;
+	}
+	ret = of_property_read_u32(plat_priv->plat_dev->dev.of_node,
+				   "qcom,bus-bw-cfg-count",
+				   &plat_priv->icc.bus_bw_cfg_count);
+	if (ret) {
+		cnss_pr_err("Failed to get Bus BW Config table size\n");
+		goto cleanup;
+	}
+	cfg_arr_size = plat_priv->icc.path_count *
+			 plat_priv->icc.bus_bw_cfg_count * CNSS_ICC_VOTE_MAX;
+	cfg_arr = kcalloc(cfg_arr_size, sizeof(*cfg_arr), GFP_KERNEL);
+	if (!cfg_arr) {
+		cnss_pr_err("Failed to alloc cfg table mem\n");
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	ret = of_property_read_u32_array(plat_priv->plat_dev->dev.of_node,
+					 "qcom,bus-bw-cfg", cfg_arr,
+					 cfg_arr_size);
+	if (ret) {
+		cnss_pr_err("Invalid Bus BW Config Table\n");
+		goto cleanup;
+	}
+
+	cnss_pr_dbg("ICC Path_Count: %d BW_CFG_Count: %d\n",
+		    plat_priv->icc.path_count, plat_priv->icc.bus_bw_cfg_count);
+
+	for (idx = 0; idx < plat_priv->icc.path_count; idx++) {
+		bus_bw_info = devm_kzalloc(dev, sizeof(*bus_bw_info),
+					   GFP_KERNEL);
+		if (!bus_bw_info) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		ret = of_property_read_string_index(dev->of_node,
+						    "interconnect-names", idx,
+						    &bus_bw_info->icc_name);
+		if (ret)
+			goto out;
+
+		bus_bw_info->icc_path =
+			of_icc_get(&plat_priv->plat_dev->dev,
+				   bus_bw_info->icc_name);
+
+		if (IS_ERR(bus_bw_info->icc_path))  {
+			ret = PTR_ERR(bus_bw_info->icc_path);
+			if (ret != -EPROBE_DEFER) {
+				cnss_pr_err("Failed to get Interconnect path for %s. Err: %d\n",
+					    bus_bw_info->icc_name, ret);
+				goto out;
+			}
+		}
+
+		bus_bw_info->cfg_table =
+			devm_kcalloc(dev, plat_priv->icc.bus_bw_cfg_count,
+				     sizeof(*bus_bw_info->cfg_table),
+				     GFP_KERNEL);
+		if (!bus_bw_info->cfg_table) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		cnss_pr_dbg("ICC Vote CFG for path: %s\n",
+			    bus_bw_info->icc_name);
+		for (i = 0, j = (idx * plat_priv->icc.bus_bw_cfg_count *
+		     CNSS_ICC_VOTE_MAX);
+		     i < plat_priv->icc.bus_bw_cfg_count;
+		     i++, j += 2) {
+			bus_bw_info->cfg_table[i].avg_bw = cfg_arr[j];
+			bus_bw_info->cfg_table[i].peak_bw = cfg_arr[j + 1];
+			cnss_pr_dbg("ICC Vote BW: %d avg: %d peak: %d\n",
+				    i, bus_bw_info->cfg_table[i].avg_bw,
+				    bus_bw_info->cfg_table[i].peak_bw);
+		}
+		list_add_tail(&bus_bw_info->list,
+			      &plat_priv->icc.list_head);
+	}
+	kfree(cfg_arr);
+	return 0;
+out:
+	list_for_each_entry_safe(bus_bw_info, tmp,
+				 &plat_priv->icc.list_head, list) {
+		list_del(&bus_bw_info->list);
+	}
+cleanup:
+	kfree(cfg_arr);
+	memset(&plat_priv->icc, 0, sizeof(plat_priv->icc));
+	return ret;
+}
+
+static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_bus_bw_info *bus_bw_info, *tmp;
+
+	list_for_each_entry_safe(bus_bw_info, tmp,
+				 &plat_priv->icc.list_head, list) {
+		list_del(&bus_bw_info->list);
+		if (bus_bw_info->icc_path)
+			icc_put(bus_bw_info->icc_path);
+	}
+	memset(&plat_priv->icc, 0, sizeof(plat_priv->icc));
+}
+#else
+static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv) {}
+#endif /* CONFIG_INTERCONNECT */
+
+static void cnss_daemon_connection_update_cb(void *cb_ctx, bool status)
+{
+	struct cnss_plat_data *plat_priv = cb_ctx;
+
+	if (!plat_priv) {
+		cnss_pr_err("%s: Invalid context\n", __func__);
+		return;
+	}
+	if (status) {
+		cnss_pr_info("CNSS Daemon connected\n");
+		set_bit(CNSS_DAEMON_CONNECTED, &plat_priv->driver_state);
+		complete(&plat_priv->daemon_connected);
+	} else {
+		cnss_pr_info("CNSS Daemon disconnected\n");
+		reinit_completion(&plat_priv->daemon_connected);
+		clear_bit(CNSS_DAEMON_CONNECTED, &plat_priv->driver_state);
+	}
+}
+
+static ssize_t enable_hds_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	unsigned int enable_hds = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (sscanf(buf, "%du", &enable_hds) != 1) {
+		cnss_pr_err("Invalid enable_hds sysfs command\n");
+		return -EINVAL;
+	}
+
+	if (enable_hds)
+		plat_priv->hds_enabled = true;
+	else
+		plat_priv->hds_enabled = false;
+
+	cnss_pr_dbg("%s HDS file download, count is %zu\n",
+		    plat_priv->hds_enabled ? "Enable" : "Disable", count);
+
+	return count;
+}
+
+static ssize_t recovery_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	u32 buf_size = PAGE_SIZE;
+	u32 curr_len = 0;
+	u32 buf_written = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	buf_written = scnprintf(buf, buf_size,
+				"Usage: echo [recovery_bitmap] > /sys/kernel/cnss/recovery\n"
+				"BIT0 -- wlan fw recovery\n"
+				"BIT1 -- wlan pcss recovery\n"
+				"---------------------------------\n");
+	curr_len += buf_written;
+
+	buf_written = scnprintf(buf + curr_len, buf_size - curr_len,
+				"WLAN recovery %s[%d]\n",
+				plat_priv->recovery_enabled ? "Enabled" : "Disabled",
+				plat_priv->recovery_enabled);
+	curr_len += buf_written;
+
+	buf_written = scnprintf(buf + curr_len, buf_size - curr_len,
+				"WLAN PCSS recovery %s[%d]\n",
+				plat_priv->recovery_pcss_enabled ? "Enabled" : "Disabled",
+				plat_priv->recovery_pcss_enabled);
+	curr_len += buf_written;
+
+	/*
+	 * Now size of curr_len is not over page size for sure,
+	 * later if new item or none-fixed size item added, need
+	 * add check to make sure curr_len is not over page size.
+	 */
+	return curr_len;
+}
+
+static ssize_t tme_opt_file_download_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	u32 buf_size = PAGE_SIZE;
+	u32 curr_len = 0;
+	u32 buf_written = 0;
+
+	buf_written = scnprintf(buf, buf_size,
+				"Usage: echo [file_type] > /sys/kernel/cnss/tme_opt_file_download\n"
+				"file_type = sec -- For OEM_FUSE file\n"
+				"file_type = rpr -- For RPR file\n"
+				"file_type = dpr -- For DPR file\n");
+
+	curr_len += buf_written;
+	return curr_len;
+}
+
+static ssize_t time_sync_period_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%u ms\n",
+			plat_priv->ctrl_params.time_sync_period);
+}
+
+/**
+ * cnss_get_min_time_sync_period_by_vote() - Get minimum time sync period
+ * @plat_priv: Platform data structure
+ *
+ * Result: return minimum time sync period present in vote from wlan and sys
+ */
+static uint32_t cnss_get_min_time_sync_period_by_vote(struct cnss_plat_data *plat_priv)
+{
+	unsigned int i, min_time_sync_period = CNSS_TIME_SYNC_PERIOD_INVALID;
+	unsigned int time_sync_period;
+
+	for (i = 0; i < TIME_SYNC_VOTE_MAX; i++) {
+		time_sync_period = plat_priv->ctrl_params.time_sync_period_vote[i];
+		if (min_time_sync_period > time_sync_period)
+			min_time_sync_period = time_sync_period;
+	}
+
+	return min_time_sync_period;
+}
+
+static ssize_t time_sync_period_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	unsigned int time_sync_period = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (sscanf(buf, "%du", &time_sync_period) != 1) {
+		cnss_pr_err("Invalid time sync sysfs command\n");
+		return -EINVAL;
+	}
+
+	if (time_sync_period < CNSS_MIN_TIME_SYNC_PERIOD) {
+		cnss_pr_err("Invalid time sync value\n");
+		return -EINVAL;
+	}
+	plat_priv->ctrl_params.time_sync_period_vote[TIME_SYNC_VOTE_CNSS] =
+		time_sync_period;
+	time_sync_period = cnss_get_min_time_sync_period_by_vote(plat_priv);
+
+	if (time_sync_period == CNSS_TIME_SYNC_PERIOD_INVALID) {
+		cnss_pr_err("Invalid min time sync value\n");
+		return -EINVAL;
+	}
+
+	cnss_bus_update_time_sync_period(plat_priv, time_sync_period);
+
+	return count;
+}
+
+/**
+ * cnss_update_time_sync_period() - Set time sync period given by driver
+ * @dev: device structure
+ * @time_sync_period: time sync period value
+ *
+ * Update time sync period vote of driver and set minimum of time sync period
+ * from stored vote through wlan and sys config
+ * Result: return 0 for success, error in case of invalid value and no dev
+ */
+int cnss_update_time_sync_period(struct device *dev, uint32_t time_sync_period)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (time_sync_period < CNSS_MIN_TIME_SYNC_PERIOD) {
+		cnss_pr_err("Invalid time sync value\n");
+		return -EINVAL;
+	}
+
+	plat_priv->ctrl_params.time_sync_period_vote[TIME_SYNC_VOTE_WLAN] =
+		time_sync_period;
+	time_sync_period = cnss_get_min_time_sync_period_by_vote(plat_priv);
+
+	if (time_sync_period == CNSS_TIME_SYNC_PERIOD_INVALID) {
+		cnss_pr_err("Invalid min time sync value\n");
+		return -EINVAL;
+	}
+
+	cnss_bus_update_time_sync_period(plat_priv, time_sync_period);
+	return 0;
+}
+EXPORT_SYMBOL(cnss_update_time_sync_period);
+
+/**
+ * cnss_reset_time_sync_period() - Reset time sync period
+ * @dev: device structure
+ *
+ * Update time sync period vote of driver as invalid
+ * and reset minimum of time sync period from
+ * stored vote through wlan and sys config
+ * Result: return 0 for success, error in case of no dev
+ */
+int cnss_reset_time_sync_period(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	unsigned int time_sync_period = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	/* Driver vote is set to invalid in case of reset
+	 * In this case, only vote valid to check is sys config
+	 */
+	plat_priv->ctrl_params.time_sync_period_vote[TIME_SYNC_VOTE_WLAN] =
+		CNSS_TIME_SYNC_PERIOD_INVALID;
+	time_sync_period = cnss_get_min_time_sync_period_by_vote(plat_priv);
+
+	if (time_sync_period == CNSS_TIME_SYNC_PERIOD_INVALID) {
+		cnss_pr_err("Invalid min time sync value\n");
+		return -EINVAL;
+	}
+
+	cnss_bus_update_time_sync_period(plat_priv, time_sync_period);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_reset_time_sync_period);
+
+static ssize_t recovery_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	unsigned int recovery = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (sscanf(buf, "%du", &recovery) != 1) {
+		cnss_pr_err("Invalid recovery sysfs command\n");
+		return -EINVAL;
+	}
+
+	plat_priv->recovery_enabled = !!(recovery & CNSS_WLAN_RECOVERY);
+	plat_priv->recovery_pcss_enabled = !!(recovery & CNSS_PCSS_RECOVERY);
+
+	cnss_pr_dbg("%s WLAN recovery, count is %zu\n",
+		    plat_priv->recovery_enabled ? "Enable" : "Disable", count);
+	cnss_pr_dbg("%s PCSS recovery, count is %zu\n",
+		    plat_priv->recovery_pcss_enabled ? "Enable" : "Disable", count);
+
+	cnss_send_subsys_restart_level_msg(plat_priv);
+	return count;
+}
+
+static ssize_t shutdown_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	cnss_pr_dbg("Received shutdown notification\n");
+	if (plat_priv) {
+		set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state);
+		cnss_bus_update_status(plat_priv, CNSS_SYS_REBOOT);
+		del_timer(&plat_priv->fw_boot_timer);
+		complete_all(&plat_priv->power_up_complete);
+		complete_all(&plat_priv->cal_complete);
+		cnss_pr_dbg("Shutdown notification handled\n");
+	}
+
+	return count;
+}
+
+static ssize_t fs_ready_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int fs_ready = 0;
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	if (sscanf(buf, "%du", &fs_ready) != 1)
+		return -EINVAL;
+
+	cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
+		    fs_ready, count);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return count;
+	}
+
+	if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks)) {
+		cnss_pr_dbg("QMI is bypassed\n");
+		return count;
+	}
+
+	set_bit(CNSS_FS_READY, &plat_priv->driver_state);
+	if (fs_ready == FILE_SYSTEM_READY && plat_priv->cbc_enabled) {
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+				       0, NULL);
+	}
+
+	return count;
+}
+
+static ssize_t qdss_trace_start_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	wlfw_qdss_trace_start(plat_priv);
+	cnss_pr_dbg("Received QDSS start command\n");
+	return count;
+}
+
+static ssize_t qdss_trace_stop_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	u32 option = 0;
+
+	if (sscanf(buf, "%du", &option) != 1)
+		return -EINVAL;
+
+	wlfw_qdss_trace_stop(plat_priv, option);
+	cnss_pr_dbg("Received QDSS stop command\n");
+	return count;
+}
+
+static ssize_t qdss_conf_download_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	cnss_wlfw_qdss_dnld_send_sync(plat_priv);
+	cnss_pr_dbg("Received QDSS download config command\n");
+	return count;
+}
+
+static ssize_t tme_opt_file_download_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	char cmd[5];
+
+	if (sscanf(buf, "%s", cmd) != 1)
+		return -EINVAL;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return 0;
+	}
+
+	if (plat_priv->device_id == PEACH_DEVICE_ID &&
+	    cnss_bus_runtime_pm_get_sync(plat_priv) < 0)
+		goto runtime_pm_put;
+
+	if (strcmp(cmd, "sec") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_OEM_FUSE_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_OEM_FUSE_FILE_V01);
+	} else if (strcmp(cmd, "rpr") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_RPR_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_RPR_FILE_V01);
+	} else if (strcmp(cmd, "dpr") == 0) {
+		cnss_bus_load_tme_opt_file(plat_priv, WLFW_TME_LITE_DPR_FILE_V01);
+		cnss_wlfw_tme_opt_file_dnld_send_sync(plat_priv, WLFW_TME_LITE_DPR_FILE_V01);
+	}
+
+	cnss_pr_dbg("Received tme_opt_file_download indication cmd: %s\n", cmd);
+
+runtime_pm_put:
+	if (plat_priv->device_id == PEACH_DEVICE_ID)
+		cnss_bus_runtime_pm_put(plat_priv);
+	return count;
+}
+
+static ssize_t hw_trace_override_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	int tmp = 0;
+
+	if (sscanf(buf, "%du", &tmp) != 1)
+		return -EINVAL;
+
+	plat_priv->hw_trc_override = tmp;
+	cnss_pr_dbg("Received QDSS hw_trc_override indication\n");
+	return count;
+}
+
+static ssize_t charger_mode_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+	int tmp = 0;
+
+	if (sscanf(buf, "%du", &tmp) != 1)
+		return -EINVAL;
+
+	plat_priv->charger_mode = tmp;
+	cnss_pr_dbg("Received Charger Mode: %d\n", tmp);
+	return count;
+}
+
+static DEVICE_ATTR_WO(fs_ready);
+static DEVICE_ATTR_WO(shutdown);
+static DEVICE_ATTR_RW(recovery);
+static DEVICE_ATTR_WO(enable_hds);
+static DEVICE_ATTR_WO(qdss_trace_start);
+static DEVICE_ATTR_WO(qdss_trace_stop);
+static DEVICE_ATTR_WO(qdss_conf_download);
+static DEVICE_ATTR_RW(tme_opt_file_download);
+static DEVICE_ATTR_WO(hw_trace_override);
+static DEVICE_ATTR_WO(charger_mode);
+static DEVICE_ATTR_RW(time_sync_period);
+
+static struct attribute *cnss_attrs[] = {
+	&dev_attr_fs_ready.attr,
+	&dev_attr_shutdown.attr,
+	&dev_attr_recovery.attr,
+	&dev_attr_enable_hds.attr,
+	&dev_attr_qdss_trace_start.attr,
+	&dev_attr_qdss_trace_stop.attr,
+	&dev_attr_qdss_conf_download.attr,
+	&dev_attr_tme_opt_file_download.attr,
+	&dev_attr_hw_trace_override.attr,
+	&dev_attr_charger_mode.attr,
+	&dev_attr_time_sync_period.attr,
+	NULL,
+};
+
+static struct attribute_group cnss_attr_group = {
+	.attrs = cnss_attrs,
+};
+
+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];
+
+	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);
+		goto out;
+	}
+
+	/* This is only for backward compatibility. */
+	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);
+		goto rm_cnss_link;
+	}
+
+	return 0;
+
+rm_cnss_link:
+	sysfs_remove_link(kernel_kobj, cnss_name);
+out:
+	return ret;
+}
+
+static void cnss_remove_sysfs_link(struct cnss_plat_data *plat_priv)
+{
+	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)
+{
+	int ret = 0;
+
+	ret = devm_device_add_group(&plat_priv->plat_dev->dev,
+				    &cnss_attr_group);
+	if (ret) {
+		cnss_pr_err("Failed to create cnss device group, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	cnss_create_sysfs_link(plat_priv);
+
+	return 0;
+out:
+	return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
+union cnss_device_group_devres {
+	const struct attribute_group *group;
+};
+
+static void devm_cnss_group_remove(struct device *dev, void *res)
+{
+	union cnss_device_group_devres *devres = res;
+	const struct attribute_group *group = devres->group;
+
+	cnss_pr_dbg("%s: removing group %p\n", __func__, group);
+	sysfs_remove_group(&dev->kobj, group);
+}
+
+static int devm_cnss_group_match(struct device *dev, void *res, void *data)
+{
+	return ((union cnss_device_group_devres *)res) == data;
+}
+
+static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
+{
+	cnss_remove_sysfs_link(plat_priv);
+	WARN_ON(devres_release(&plat_priv->plat_dev->dev,
+			       devm_cnss_group_remove, devm_cnss_group_match,
+			       (void *)&cnss_attr_group));
+}
+#else
+static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
+{
+	cnss_remove_sysfs_link(plat_priv);
+	devm_device_remove_group(&plat_priv->plat_dev->dev, &cnss_attr_group);
+}
+#endif
+
+static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
+{
+	spin_lock_init(&plat_priv->event_lock);
+	plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
+					      WQ_UNBOUND, 1);
+	if (!plat_priv->event_wq) {
+		cnss_pr_err("Failed to create event workqueue!\n");
+		return -EFAULT;
+	}
+
+	INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
+	INIT_LIST_HEAD(&plat_priv->event_list);
+
+	return 0;
+}
+
+static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
+{
+	destroy_workqueue(plat_priv->event_wq);
+}
+
+static int cnss_reboot_notifier(struct notifier_block *nb,
+				unsigned long action,
+				void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(nb, struct cnss_plat_data, reboot_nb);
+
+	set_bit(CNSS_IN_REBOOT, &plat_priv->driver_state);
+	cnss_bus_update_status(plat_priv, CNSS_SYS_REBOOT);
+	del_timer(&plat_priv->fw_boot_timer);
+	complete_all(&plat_priv->power_up_complete);
+	complete_all(&plat_priv->cal_complete);
+	cnss_pr_dbg("Reboot is in progress with action %d\n", action);
+
+	return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_CNSS_HW_SECURE_DISABLE
+#ifdef CONFIG_CNSS_HW_SECURE_SMEM
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv)
+{
+	uint32_t *peripheralStateInfo = NULL;
+	size_t size = 0;
+
+	/* Once this flag is set, secure peripheral feature
+	 * will not be supported till next reboot
+	 */
+	if (plat_priv->sec_peri_feature_disable)
+		return 0;
+
+	peripheralStateInfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, PERISEC_SMEM_ID, &size);
+	if (IS_ERR_OR_NULL(peripheralStateInfo)) {
+		if (PTR_ERR(peripheralStateInfo) != -ENOENT &&
+		    PTR_ERR(peripheralStateInfo) != -ENODEV)
+			CNSS_ASSERT(0);
+
+		cnss_pr_dbg("Secure HW feature not enabled. ret = %d\n",
+			    PTR_ERR(peripheralStateInfo));
+		plat_priv->sec_peri_feature_disable = true;
+		return 0;
+	}
+
+	cnss_pr_dbg("Secure HW state: %d\n", *peripheralStateInfo);
+	if ((*peripheralStateInfo >> (HW_WIFI_UID - 0x500)) & 0x1)
+		set_bit(CNSS_WLAN_HW_DISABLED,
+			&plat_priv->driver_state);
+	else
+		clear_bit(CNSS_WLAN_HW_DISABLED,
+			  &plat_priv->driver_state);
+
+	return 0;
+}
+#else
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv)
+{
+	struct Object client_env;
+	struct Object app_object;
+	u32 wifi_uid = HW_WIFI_UID;
+	union ObjectArg obj_arg[2] = {{{0, 0}}};
+	int ret;
+	u8 state = 0;
+
+	/* Once this flag is set, secure peripheral feature
+	 * will not be supported till next reboot
+	 */
+	if (plat_priv->sec_peri_feature_disable)
+		return 0;
+
+	/* get rootObj */
+	ret = get_client_env_object(&client_env);
+	if (ret) {
+		cnss_pr_dbg("Failed to get client_env_object, ret: %d\n", ret);
+		goto end;
+	}
+	ret = IClientEnv_open(client_env, HW_STATE_UID, &app_object);
+	if (ret) {
+		cnss_pr_dbg("Failed to get app_object, ret: %d\n",  ret);
+		if (ret == FEATURE_NOT_SUPPORTED) {
+			ret = 0; /* Do not Assert */
+			plat_priv->sec_peri_feature_disable = true;
+			cnss_pr_dbg("Secure HW feature not supported\n");
+		}
+		goto exit_release_clientenv;
+	}
+
+	obj_arg[0].b = (struct ObjectBuf) {&wifi_uid, sizeof(u32)};
+	obj_arg[1].b = (struct ObjectBuf) {&state, sizeof(u8)};
+	ret = Object_invoke(app_object, HW_OP_GET_STATE, obj_arg,
+			    ObjectCounts_pack(1, 1, 0, 0));
+
+	cnss_pr_dbg("SMC invoke ret: %d state: %d\n", ret, state);
+	if (ret) {
+		if (ret == PERIPHERAL_NOT_FOUND) {
+			ret = 0; /* Do not Assert */
+			plat_priv->sec_peri_feature_disable = true;
+			cnss_pr_dbg("Secure HW mode is not updated. Peripheral not found\n");
+		}
+		goto exit_release_app_obj;
+	}
+
+	if (state == 1)
+		set_bit(CNSS_WLAN_HW_DISABLED,
+			&plat_priv->driver_state);
+	else
+		clear_bit(CNSS_WLAN_HW_DISABLED,
+			  &plat_priv->driver_state);
+
+exit_release_app_obj:
+	Object_release(app_object);
+exit_release_clientenv:
+	Object_release(client_env);
+end:
+	if (ret) {
+		cnss_pr_err("Unable to get HW disable status\n");
+		CNSS_ASSERT(0);
+	}
+	return ret;
+}
+#endif
+#else
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_DISABLE_CNSS_SRAM_DUMP
+static void cnss_sram_dump_init(struct cnss_plat_data *plat_priv)
+{
+}
+#else
+static void cnss_sram_dump_init(struct cnss_plat_data *plat_priv)
+{
+	if (plat_priv->device_id == QCA6490_DEVICE_ID &&
+	    cnss_get_host_build_type() == QMI_HOST_BUILD_TYPE_PRIMARY_V01)
+		plat_priv->sram_dump = kcalloc(SRAM_DUMP_SIZE, 1, GFP_KERNEL);
+}
+#endif
+
+#if IS_ENABLED(CONFIG_WCNSS_MEM_PRE_ALLOC)
+static void cnss_initialize_mem_pool(unsigned long device_id)
+{
+	cnss_initialize_prealloc_pool(device_id);
+}
+static void cnss_deinitialize_mem_pool(void)
+{
+	cnss_deinitialize_prealloc_pool();
+}
+#else
+static void cnss_initialize_mem_pool(unsigned long device_id)
+{
+}
+static void cnss_deinitialize_mem_pool(void)
+{
+}
+#endif
+
+static int cnss_misc_init(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	ret = cnss_init_sol_gpio(plat_priv);
+	if (ret)
+		return ret;
+
+	timer_setup(&plat_priv->fw_boot_timer,
+		    cnss_bus_fw_boot_timeout_hdlr, 0);
+
+	ret = device_init_wakeup(&plat_priv->plat_dev->dev, true);
+	if (ret)
+		cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
+			    ret);
+
+	INIT_WORK(&plat_priv->recovery_work, cnss_recovery_work_handler);
+	init_completion(&plat_priv->power_up_complete);
+	init_completion(&plat_priv->cal_complete);
+	init_completion(&plat_priv->rddm_complete);
+	init_completion(&plat_priv->recovery_complete);
+	init_completion(&plat_priv->daemon_connected);
+	mutex_init(&plat_priv->dev_lock);
+	mutex_init(&plat_priv->driver_ops_lock);
+
+	plat_priv->reboot_nb.notifier_call = cnss_reboot_notifier;
+	ret = register_reboot_notifier(&plat_priv->reboot_nb);
+	if (ret)
+		cnss_pr_err("Failed to register reboot notifier, err = %d\n",
+			    ret);
+
+	plat_priv->recovery_ws =
+		wakeup_source_register(&plat_priv->plat_dev->dev,
+				       "CNSS_FW_RECOVERY");
+	if (!plat_priv->recovery_ws)
+		cnss_pr_err("Failed to setup FW recovery wake source\n");
+
+	ret = cnss_plat_ipc_register(CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01,
+				     cnss_daemon_connection_update_cb,
+				     plat_priv);
+	if (ret)
+		cnss_pr_err("QMI IPC connection call back register failed, err = %d\n",
+			    ret);
+
+	cnss_sram_dump_init(plat_priv);
+
+	if (of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				  "qcom,rc-ep-short-channel"))
+		cnss_set_feature_list(plat_priv, CNSS_RC_EP_ULTRASHORT_CHANNEL_V01);
+	if (plat_priv->device_id == PEACH_DEVICE_ID)
+		cnss_set_feature_list(plat_priv, CNSS_AUX_UC_SUPPORT_V01);
+
+	return 0;
+}
+
+#ifdef CONFIG_DISABLE_CNSS_SRAM_DUMP
+static void cnss_sram_dump_deinit(struct cnss_plat_data *plat_priv)
+{
+}
+#else
+static void cnss_sram_dump_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (plat_priv->device_id == QCA6490_DEVICE_ID &&
+	    cnss_get_host_build_type() == QMI_HOST_BUILD_TYPE_PRIMARY_V01)
+		kfree(plat_priv->sram_dump);
+}
+#endif
+
+static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
+{
+	cnss_plat_ipc_unregister(CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01,
+				 plat_priv);
+	complete_all(&plat_priv->recovery_complete);
+	complete_all(&plat_priv->rddm_complete);
+	complete_all(&plat_priv->cal_complete);
+	complete_all(&plat_priv->power_up_complete);
+	complete_all(&plat_priv->daemon_connected);
+	device_init_wakeup(&plat_priv->plat_dev->dev, false);
+	unregister_reboot_notifier(&plat_priv->reboot_nb);
+	del_timer(&plat_priv->fw_boot_timer);
+	wakeup_source_unregister(plat_priv->recovery_ws);
+	cnss_deinit_sol_gpio(plat_priv);
+	cnss_sram_dump_deinit(plat_priv);
+	kfree(plat_priv->on_chip_pmic_board_ids);
+}
+
+static void cnss_init_time_sync_period_default(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->ctrl_params.time_sync_period_vote[TIME_SYNC_VOTE_WLAN] =
+		CNSS_TIME_SYNC_PERIOD_INVALID;
+	plat_priv->ctrl_params.time_sync_period_vote[TIME_SYNC_VOTE_CNSS] =
+		CNSS_TIME_SYNC_PERIOD_DEFAULT;
+}
+
+static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
+{
+	plat_priv->ctrl_params.quirks = CNSS_QUIRKS_DEFAULT;
+
+	plat_priv->cbc_enabled = !IS_ENABLED(CONFIG_CNSS_EMULATION) &&
+		of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				      "qcom,wlan-cbc-enabled");
+
+	plat_priv->ctrl_params.mhi_timeout = CNSS_MHI_TIMEOUT_DEFAULT;
+	plat_priv->ctrl_params.mhi_m2_timeout = CNSS_MHI_M2_TIMEOUT_DEFAULT;
+	plat_priv->ctrl_params.qmi_timeout = CNSS_QMI_TIMEOUT_DEFAULT;
+	plat_priv->ctrl_params.bdf_type = CNSS_BDF_TYPE_DEFAULT;
+	plat_priv->ctrl_params.time_sync_period = CNSS_TIME_SYNC_PERIOD_DEFAULT;
+	cnss_init_time_sync_period_default(plat_priv);
+	/* Set adsp_pc_enabled default value to true as ADSP pc is always
+	 * enabled by default
+	 */
+	plat_priv->adsp_pc_enabled = true;
+}
+
+static void cnss_get_pm_domain_info(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+
+	plat_priv->use_pm_domain =
+		of_property_read_bool(dev->of_node, "use-pm-domain");
+
+	cnss_pr_dbg("use-pm-domain is %d\n", plat_priv->use_pm_domain);
+}
+
+static void cnss_get_wlaon_pwr_ctrl_info(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+
+	plat_priv->set_wlaon_pwr_ctrl =
+		of_property_read_bool(dev->of_node, "qcom,set-wlaon-pwr-ctrl");
+
+	cnss_pr_dbg("set_wlaon_pwr_ctrl is %d\n",
+		    plat_priv->set_wlaon_pwr_ctrl);
+}
+
+static bool cnss_use_fw_path_with_prefix(struct cnss_plat_data *plat_priv)
+{
+	return (of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				      "qcom,converged-dt") ||
+		of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				      "qcom,same-dt-multi-dev") ||
+		of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				      "qcom,multi-wlan-exchg"));
+}
+
+static const struct platform_device_id cnss_platform_id_table[] = {
+	{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
+	{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
+	{ .name = "qca6390", .driver_data = QCA6390_DEVICE_ID, },
+	{ .name = "qca6490", .driver_data = QCA6490_DEVICE_ID, },
+	{ .name = "kiwi", .driver_data = KIWI_DEVICE_ID, },
+	{ .name = "mango", .driver_data = MANGO_DEVICE_ID, },
+	{ .name = "peach", .driver_data = PEACH_DEVICE_ID, },
+	{ .name = "qcaconv", .driver_data = 0, },
+	{ },
+};
+
+static const struct of_device_id cnss_of_match_table[] = {
+	{
+		.compatible = "qcom,cnss",
+		.data = (void *)&cnss_platform_id_table[0]},
+	{
+		.compatible = "qcom,cnss-qca6290",
+		.data = (void *)&cnss_platform_id_table[1]},
+	{
+		.compatible = "qcom,cnss-qca6390",
+		.data = (void *)&cnss_platform_id_table[2]},
+	{
+		.compatible = "qcom,cnss-qca6490",
+		.data = (void *)&cnss_platform_id_table[3]},
+	{
+		.compatible = "qcom,cnss-kiwi",
+		.data = (void *)&cnss_platform_id_table[4]},
+	{
+		.compatible = "qcom,cnss-mango",
+		.data = (void *)&cnss_platform_id_table[5]},
+	{
+		.compatible = "qcom,cnss-peach",
+		.data = (void *)&cnss_platform_id_table[6]},
+	{
+		.compatible = "qcom,cnss-qca-converged",
+		.data = (void *)&cnss_platform_id_table[7]},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, cnss_of_match_table);
+
+static inline bool
+cnss_use_nv_mac(struct cnss_plat_data *plat_priv)
+{
+	return of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				     "use-nv-mac");
+}
+
+static int cnss_get_dev_cfg_node(struct cnss_plat_data *plat_priv)
+{
+	struct device_node *child;
+	u32 id, i;
+	int id_n,  device_identifier_gpio, ret;
+	u8 gpio_value;
+
+
+	if (plat_priv->dt_type != CNSS_DTT_CONVERGED)
+		return 0;
+
+	/* Parses the wlan_sw_ctrl gpio which is used to identify device */
+	ret = cnss_get_wlan_sw_ctrl(plat_priv);
+	if (ret) {
+		cnss_pr_dbg("Failed to parse wlan_sw_ctrl gpio, error:%d", ret);
+		return ret;
+	}
+
+	device_identifier_gpio = plat_priv->pinctrl_info.wlan_sw_ctrl_gpio;
+
+	gpio_value = gpio_get_value(device_identifier_gpio);
+	cnss_pr_dbg("Value of Device Identifier GPIO: %d\n", gpio_value);
+
+	for_each_available_child_of_node(plat_priv->plat_dev->dev.of_node,
+					 child) {
+		if (strcmp(child->name, "chip_cfg"))
+			continue;
+
+		id_n = of_property_count_u32_elems(child, "supported-ids");
+		if (id_n <= 0) {
+			cnss_pr_err("Device id is NOT set\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < id_n; i++) {
+			ret = of_property_read_u32_index(child,
+							 "supported-ids",
+							 i, &id);
+			if (ret) {
+				cnss_pr_err("Failed to read supported ids\n");
+				return -EINVAL;
+			}
+
+			if (gpio_value && id == QCA6490_DEVICE_ID) {
+				plat_priv->plat_dev->dev.of_node = child;
+				plat_priv->device_id = QCA6490_DEVICE_ID;
+				cnss_utils_update_device_type(CNSS_HSP_DEVICE_TYPE);
+				cnss_pr_dbg("got node[%s@%d] for device[0x%x]\n",
+					    child->name, i, id);
+				return 0;
+			} else if (!gpio_value && id == KIWI_DEVICE_ID) {
+				plat_priv->plat_dev->dev.of_node = child;
+				plat_priv->device_id = KIWI_DEVICE_ID;
+				cnss_utils_update_device_type(CNSS_HMT_DEVICE_TYPE);
+				cnss_pr_dbg("got node[%s@%d] for device[0x%x]\n",
+					    child->name, i, id);
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static inline u32
+cnss_dt_type(struct cnss_plat_data *plat_priv)
+{
+	bool is_converged_dt = of_property_read_bool(
+		plat_priv->plat_dev->dev.of_node, "qcom,converged-dt");
+	bool is_multi_wlan_xchg;
+
+	if (is_converged_dt)
+		return CNSS_DTT_CONVERGED;
+
+	is_multi_wlan_xchg = of_property_read_bool(
+		plat_priv->plat_dev->dev.of_node, "qcom,multi-wlan-exchg");
+
+	if (is_multi_wlan_xchg)
+		return CNSS_DTT_MULTIEXCHG;
+	return CNSS_DTT_LEGACY;
+}
+
+static int cnss_wlan_device_init(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	int retry = 0;
+
+	if (test_bit(SKIP_DEVICE_BOOT, &plat_priv->ctrl_params.quirks))
+		return 0;
+
+retry:
+	ret = cnss_power_on_device(plat_priv, true);
+	if (ret)
+		goto end;
+
+	ret = cnss_bus_init(plat_priv);
+	if (ret) {
+		if ((ret != -EPROBE_DEFER) &&
+		    retry++ < POWER_ON_RETRY_MAX_TIMES) {
+			cnss_power_off_device(plat_priv);
+			cnss_pr_dbg("Retry cnss_bus_init #%d\n", retry);
+			msleep(POWER_ON_RETRY_DELAY_MS * retry);
+			goto retry;
+		}
+		goto power_off;
+	}
+	return 0;
+
+power_off:
+	cnss_power_off_device(plat_priv);
+end:
+	return ret;
+}
+
+int cnss_wlan_hw_enable(void)
+{
+	struct cnss_plat_data *plat_priv;
+	int ret = 0;
+
+	if (cnss_is_dual_wlan_enabled())
+		plat_priv = cnss_get_first_plat_priv(NULL);
+	else
+		plat_priv = cnss_get_plat_priv(NULL);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	clear_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state);
+
+	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))
+			CNSS_ASSERT(0);
+		return ret;
+	}
+
+	if (test_bit(CNSS_FS_READY, &plat_priv->driver_state))
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+				       0, NULL);
+
+register_driver:
+	if (plat_priv->driver_ops)
+		ret = cnss_wlan_register_driver(plat_priv->driver_ops);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_hw_enable);
+
+int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	/* If IMS server is connected, return success without QMI send */
+	if (test_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Ignore host request as IMS server is connected");
+		return ret;
+	}
+
+	ret = cnss_wlfw_send_host_wfc_call_status(plat_priv, cfg);
+
+	return ret;
+}
+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;
+	struct cnss_plat_data *plat_priv;
+	const struct of_device_id *of_id;
+	const struct platform_device_id *device_id;
+
+	if (cnss_get_plat_priv(plat_dev)) {
+		cnss_pr_err("Driver is already initialized!\n");
+		ret = -EEXIST;
+		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");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	device_id = of_id->data;
+
+	plat_priv = devm_kzalloc(&plat_dev->dev, sizeof(*plat_priv),
+				 GFP_KERNEL);
+	if (!plat_priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	plat_priv->plat_dev = plat_dev;
+	plat_priv->dev_node = NULL;
+	plat_priv->device_id = device_id->driver_data;
+	plat_priv->dt_type = cnss_dt_type(plat_priv);
+	cnss_pr_dbg("Probing platform driver from dt type: %d\n",
+		    plat_priv->dt_type);
+
+	plat_priv->use_fw_path_with_prefix =
+		cnss_use_fw_path_with_prefix(plat_priv);
+
+	ret = cnss_get_dev_cfg_node(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get device cfg node, err = %d\n", ret);
+		goto reset_plat_dev;
+	}
+
+	cnss_initialize_mem_pool(plat_priv->device_id);
+
+	ret = cnss_get_pld_bus_ops_name(plat_priv);
+	if (ret)
+		cnss_pr_vdbg("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);
+	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);
+
+	cnss_get_pm_domain_info(plat_priv);
+	cnss_get_wlaon_pwr_ctrl_info(plat_priv);
+	cnss_power_misc_params_init(plat_priv);
+	cnss_pci_of_switch_type_init(plat_priv);
+	cnss_get_tcs_info(plat_priv);
+	cnss_get_cpr_info(plat_priv);
+	cnss_aop_interface_init(plat_priv);
+	cnss_init_control_params(plat_priv);
+
+	ret = cnss_get_resources(plat_priv);
+	if (ret)
+		goto reset_ctx;
+
+	ret = cnss_register_esoc(plat_priv);
+	if (ret)
+		goto free_res;
+
+	ret = cnss_register_bus_scale(plat_priv);
+	if (ret)
+		goto unreg_esoc;
+
+	ret = cnss_create_sysfs(plat_priv);
+	if (ret)
+		goto unreg_bus_scale;
+
+	ret = cnss_event_work_init(plat_priv);
+	if (ret)
+		goto remove_sysfs;
+
+	ret = cnss_dms_init(plat_priv);
+	if (ret)
+		goto deinit_event_work;
+
+	ret = cnss_debugfs_create(plat_priv);
+	if (ret)
+		goto deinit_dms;
+
+	ret = cnss_misc_init(plat_priv);
+	if (ret)
+		goto destroy_debugfs;
+
+	ret = cnss_wlan_hw_disable_check(plat_priv);
+	if (ret)
+		goto deinit_misc;
+
+	/* Make sure all platform related init are done before
+	 * device power on and bus init.
+	 */
+	if (!test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		ret = cnss_wlan_device_init(plat_priv);
+		if (ret)
+			goto deinit_misc;
+	} else {
+		cnss_pr_info("WLAN HW Disabled. Defer PCI enumeration\n");
+	}
+	cnss_register_coex_service(plat_priv);
+	cnss_register_ims_service(plat_priv);
+
+	mutex_init(&plat_priv->tcdev_lock);
+	INIT_LIST_HEAD(&plat_priv->cnss_tcdev_list);
+
+	cnss_pr_info("Platform driver probed successfully.\n");
+
+	return 0;
+
+deinit_misc:
+	cnss_misc_deinit(plat_priv);
+destroy_debugfs:
+	cnss_debugfs_destroy(plat_priv);
+deinit_dms:
+	cnss_cancel_dms_work();
+	cnss_dms_deinit(plat_priv);
+deinit_event_work:
+	cnss_event_work_deinit(plat_priv);
+remove_sysfs:
+	cnss_remove_sysfs(plat_priv);
+unreg_bus_scale:
+	cnss_unregister_bus_scale(plat_priv);
+unreg_esoc:
+	cnss_unregister_esoc(plat_priv);
+free_res:
+	cnss_put_resources(plat_priv);
+reset_ctx:
+	cnss_aop_interface_deinit(plat_priv);
+	platform_set_drvdata(plat_dev, NULL);
+	cnss_deinitialize_mem_pool();
+reset_plat_dev:
+	cnss_clear_plat_priv(plat_priv);
+out:
+	return ret;
+}
+
+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);
+	cnss_bus_deinit(plat_priv);
+	cnss_misc_deinit(plat_priv);
+	cnss_debugfs_destroy(plat_priv);
+	cnss_cancel_dms_work();
+	cnss_dms_deinit(plat_priv);
+	cnss_qmi_deinit(plat_priv);
+	cnss_event_work_deinit(plat_priv);
+	cnss_remove_sysfs(plat_priv);
+	cnss_unregister_bus_scale(plat_priv);
+	cnss_unregister_esoc(plat_priv);
+	cnss_put_resources(plat_priv);
+	cnss_aop_interface_deinit(plat_priv);
+	cnss_deinitialize_mem_pool();
+	platform_set_drvdata(plat_dev, NULL);
+	cnss_clear_plat_priv(plat_priv);
+
+	return 0;
+}
+
+static struct platform_driver cnss_platform_driver = {
+	.probe  = cnss_probe,
+	.remove = cnss_remove,
+	.driver = {
+		.name = "cnss2",
+		.of_match_table = cnss_of_match_table,
+#ifdef CONFIG_CNSS_ASYNC
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+	},
+};
+
+static bool cnss_check_compatible_node(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_matching_node(dn, cnss_of_match_table) {
+		if (of_device_is_available(dn)) {
+			cnss_allow_driver_loading = true;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/**
+ * cnss_is_valid_dt_node_found - Check if valid device tree node present
+ *
+ * Valid device tree node means a node with "compatible" property from the
+ * device match table and "status" property is not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool cnss_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_matching_node(dn, cnss_of_match_table) {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+static int __init cnss_initialize(void)
+{
+	int ret = 0;
+
+	if (!cnss_is_valid_dt_node_found())
+		return -ENODEV;
+
+	if (!cnss_check_compatible_node())
+		return ret;
+
+	cnss_debug_init();
+	ret = platform_driver_register(&cnss_platform_driver);
+	if (ret)
+		cnss_debug_deinit();
+
+	ret = cnss_genl_init();
+	if (ret < 0)
+		cnss_pr_err("CNSS genl init failed %d\n", ret);
+
+	cnss_init_plat_env_count();
+	return ret;
+}
+
+static void __exit cnss_exit(void)
+{
+	cnss_genl_exit();
+	platform_driver_unregister(&cnss_platform_driver);
+	cnss_debug_deinit();
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS2 Platform Driver");

+ 772 - 0
qcom/opensource/wlan/platform/cnss2/main.h

@@ -0,0 +1,772 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CNSS_MAIN_H
+#define _CNSS_MAIN_H
+
+#if IS_ENABLED(CONFIG_ARM) || IS_ENABLED(CONFIG_ARM64)
+#include <asm/arch_timer.h>
+#endif
+#if IS_ENABLED(CONFIG_ESOC)
+#include <linux/esoc_client.h>
+#endif
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+#include <linux/interconnect.h>
+#endif
+#include <linux/mailbox_client.h>
+#include <linux/pm_qos.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/time64.h>
+#if IS_ENABLED(CONFIG_MSM_QMP)
+#include <linux/mailbox/qmp.h>
+#endif
+#ifdef CONFIG_CNSS_OUT_OF_TREE
+#include "cnss2.h"
+#else
+#include <net/cnss2.h>
+#endif
+#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2) || IS_ENABLED(CONFIG_QCOM_MINIDUMP)
+#include <soc/qcom/memory_dump.h>
+#endif
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART) || \
+	IS_ENABLED(CONFIG_QCOM_RAMDUMP)
+#include <soc/qcom/qcom_ramdump.h>
+#endif
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#endif
+#include <linux/iommu.h>
+#include "qmi.h"
+#include "cnss_prealloc.h"
+#include "cnss_common.h"
+
+#define MAX_NO_OF_MAC_ADDR		4
+#define QMI_WLFW_MAX_TIMESTAMP_LEN	32
+#define QMI_WLFW_MAX_BUILD_ID_LEN	128
+#define CNSS_RDDM_TIMEOUT_MS		20000
+#define RECOVERY_TIMEOUT		60000
+#define WLAN_WD_TIMEOUT_MS		60000
+#define WLAN_COLD_BOOT_CAL_TIMEOUT	60000
+#define WLAN_MISSION_MODE_TIMEOUT	30000
+#define TIME_CLOCK_FREQ_HZ		19200000
+#define CNSS_RAMDUMP_MAGIC		0x574C414E
+#define CNSS_RAMDUMP_VERSION		0
+#define MAX_FIRMWARE_NAME_LEN		40
+#define FW_V1_NUMBER                    1
+#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
+
+#define CNSS_EVENT_SYNC   BIT(0)
+#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
+#define CNSS_EVENT_UNKILLABLE BIT(2)
+#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
+				CNSS_EVENT_UNINTERRUPTIBLE)
+#define CNSS_EVENT_SYNC_UNKILLABLE (CNSS_EVENT_SYNC | CNSS_EVENT_UNKILLABLE)
+#define QMI_WLFW_MAX_TME_OPT_FILE_NUM 3
+#define TME_OEM_FUSE_FILE_NAME		"peach_sec.dat"
+#define TME_RPR_FILE_NAME		"peach_rpr.bin"
+#define TME_DPR_FILE_NAME		"peach_dpr.bin"
+
+enum cnss_dt_type {
+	CNSS_DTT_LEGACY = 0,
+	CNSS_DTT_CONVERGED = 1,
+	CNSS_DTT_MULTIEXCHG = 2
+};
+
+enum cnss_dev_bus_type {
+	CNSS_BUS_NONE = -1,
+	CNSS_BUS_PCI,
+	CNSS_BUS_MAX
+};
+
+struct cnss_vreg_cfg {
+	const char *name;
+	u32 min_uv;
+	u32 max_uv;
+	u32 load_ua;
+	u32 delay_us;
+	u32 need_unvote;
+};
+
+struct cnss_vreg_info {
+	struct list_head list;
+	struct regulator *reg;
+	struct cnss_vreg_cfg cfg;
+	u32 enabled;
+};
+
+enum cnss_vreg_type {
+	CNSS_VREG_PRIM,
+};
+
+enum cnss_pci_switch_type {
+	PCIE_DIRECT_ATTACH = 0,
+	PCIE_SWITCH_NTN3,
+};
+
+struct cnss_clk_cfg {
+	const char *name;
+	u32 freq;
+	u32 required;
+};
+
+struct cnss_clk_info {
+	struct list_head list;
+	struct clk *clk;
+	struct cnss_clk_cfg cfg;
+	u32 enabled;
+};
+
+struct cnss_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *bootstrap_active;
+	struct pinctrl_state *sol_default;
+	struct pinctrl_state *wlan_en_active;
+	struct pinctrl_state *wlan_en_sleep;
+	struct pinctrl_state *sw_ctrl;
+	struct pinctrl_state *sw_ctrl_wl_cx;
+	int bt_en_gpio;
+	int wlan_en_gpio;
+	int xo_clk_gpio; /*qca6490 only */
+	int sw_ctrl_gpio;
+	int wlan_sw_ctrl_gpio;
+};
+
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+struct cnss_subsys_info {
+	struct subsys_device *subsys_device;
+	struct subsys_desc subsys_desc;
+	void *subsys_handle;
+};
+#endif
+
+struct cnss_ramdump_info {
+	void *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_va;
+	phys_addr_t ramdump_pa;
+#if IS_ENABLED(CONFIG_QCOM_MEMORY_DUMP_V2)
+	struct msm_dump_data dump_data;
+#endif
+};
+
+struct cnss_dump_seg {
+	unsigned long address;
+	void *v_address;
+	unsigned long size;
+	u32 type;
+};
+
+struct cnss_dump_data {
+	u32 version;
+	u32 magic;
+	char name[32];
+	phys_addr_t paddr;
+	int nentries;
+	u32 seg_version;
+};
+
+struct cnss_ramdump_info_v2 {
+	void *ramdump_dev;
+	unsigned long ramdump_size;
+	void *dump_data_vaddr;
+	u8 dump_data_valid;
+	struct cnss_dump_data dump_data;
+};
+
+#if IS_ENABLED(CONFIG_ESOC)
+struct cnss_esoc_info {
+	struct esoc_desc *esoc_desc;
+	u8 notify_modem_status;
+	void *modem_notify_handler;
+	int modem_current_status;
+};
+#endif
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+/**
+ * struct cnss_bus_bw_cfg - Interconnect vote data
+ * @avg_bw: Vote for average bandwidth
+ * @peak_bw: Vote for peak bandwidth
+ */
+struct cnss_bus_bw_cfg {
+	u32 avg_bw;
+	u32 peak_bw;
+};
+
+/* Number of bw votes (avg, peak) entries that ICC requires */
+#define CNSS_ICC_VOTE_MAX 2
+
+/**
+ * struct cnss_bus_bw_info - Bus bandwidth config for interconnect path
+ * @list: Kernel linked list
+ * @icc_name: Name of interconnect path as defined in Device tree
+ * @icc_path: Interconnect path data structure
+ * @cfg_table: Interconnect vote data for average and peak bandwidth
+ */
+struct cnss_bus_bw_info {
+	struct list_head list;
+	const char *icc_name;
+	struct icc_path *icc_path;
+	struct cnss_bus_bw_cfg *cfg_table;
+};
+#endif
+
+/**
+ * struct cnss_interconnect_cfg - CNSS platform interconnect config
+ * @list_head: List of interconnect path bandwidth configs
+ * @path_count: Count of interconnect path configured in device tree
+ * @current_bw_vote: WLAN driver provided bandwidth vote
+ * @bus_bw_cfg_count: Number of bandwidth configs for voting. It is the array
+ *                    size of struct cnss_bus_bw_info.cfg_table
+ */
+struct cnss_interconnect_cfg {
+	struct list_head list_head;
+	u32 path_count;
+	int current_bw_vote;
+	u32 bus_bw_cfg_count;
+};
+
+struct cnss_fw_mem {
+	size_t size;
+	void *va;
+	phys_addr_t pa;
+	u8 valid;
+	u32 type;
+	unsigned long attrs;
+};
+
+struct wlfw_rf_chip_info {
+	u32 chip_id;
+	u32 chip_family;
+};
+
+struct wlfw_rf_board_info {
+	u32 board_id;
+};
+
+struct wlfw_soc_info {
+	u32 soc_id;
+};
+
+struct wlfw_fw_version_info {
+	u32 fw_version;
+	char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN + 1];
+};
+
+enum cnss_mem_type {
+	CNSS_MEM_TYPE_MSA,
+	CNSS_MEM_TYPE_DDR,
+	CNSS_MEM_BDF,
+	CNSS_MEM_M3,
+	CNSS_MEM_CAL_V01,
+	CNSS_MEM_DPD_V01,
+	CNSS_MEM_AUX,
+};
+
+enum cnss_fw_dump_type {
+	CNSS_FW_IMAGE,
+	CNSS_FW_RDDM,
+	CNSS_FW_REMOTE_HEAP,
+	CNSS_FW_CAL,
+	CNSS_FW_DUMP_TYPE_MAX,
+};
+
+struct cnss_dump_entry {
+	int type;
+	u32 entry_start;
+	u32 entry_num;
+};
+
+struct cnss_dump_meta_info {
+	u32 magic;
+	u32 version;
+	u32 chipset;
+	u32 total_entries;
+	struct cnss_dump_entry entry[CNSS_FW_DUMP_TYPE_MAX];
+};
+
+struct cnss_host_dump_meta_info {
+	u32 magic;
+	u32 version;
+	u32 chipset;
+	u32 total_entries;
+	struct cnss_dump_entry entry[CNSS_HOST_DUMP_TYPE_MAX];
+};
+
+enum cnss_driver_event_type {
+	CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+	CNSS_DRIVER_EVENT_SERVER_EXIT,
+	CNSS_DRIVER_EVENT_REQUEST_MEM,
+	CNSS_DRIVER_EVENT_FW_MEM_READY,
+	CNSS_DRIVER_EVENT_FW_READY,
+	CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+	CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+	CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+	CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+	CNSS_DRIVER_EVENT_RECOVERY,
+	CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+	CNSS_DRIVER_EVENT_POWER_UP,
+	CNSS_DRIVER_EVENT_POWER_DOWN,
+	CNSS_DRIVER_EVENT_IDLE_RESTART,
+	CNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+	CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND,
+	CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND,
+	CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
+	CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE,
+	CNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
+	CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA,
+	CNSS_DRIVER_EVENT_MAX,
+};
+
+enum cnss_driver_state {
+	CNSS_QMI_WLFW_CONNECTED = 0,
+	CNSS_FW_MEM_READY,
+	CNSS_FW_READY,
+	CNSS_IN_COLD_BOOT_CAL,
+	CNSS_DRIVER_LOADING,
+	CNSS_DRIVER_UNLOADING = 5,
+	CNSS_DRIVER_IDLE_RESTART,
+	CNSS_DRIVER_IDLE_SHUTDOWN,
+	CNSS_DRIVER_PROBED,
+	CNSS_DRIVER_RECOVERY,
+	CNSS_FW_BOOT_RECOVERY = 10,
+	CNSS_DEV_ERR_NOTIFY,
+	CNSS_DRIVER_DEBUG,
+	CNSS_COEX_CONNECTED,
+	CNSS_IMS_CONNECTED,
+	CNSS_IN_SUSPEND_RESUME = 15,
+	CNSS_IN_REBOOT,
+	CNSS_COLD_BOOT_CAL_DONE,
+	CNSS_IN_PANIC,
+	CNSS_QMI_DEL_SERVER,
+	CNSS_QMI_DMS_CONNECTED = 20,
+	CNSS_DAEMON_CONNECTED,
+	CNSS_PCI_PROBE_DONE,
+	CNSS_DRIVER_REGISTER,
+	CNSS_WLAN_HW_DISABLED,
+	CNSS_FS_READY = 25,
+	CNSS_DRIVER_REGISTERED,
+	CNSS_DMS_DEL_SERVER,
+	CNSS_POWER_OFF,
+};
+
+struct cnss_recovery_data {
+	enum cnss_recovery_reason reason;
+};
+
+enum cnss_pins {
+	CNSS_WLAN_EN,
+	CNSS_PCIE_TXP,
+	CNSS_PCIE_TXN,
+	CNSS_PCIE_RXP,
+	CNSS_PCIE_RXN,
+	CNSS_PCIE_REFCLKP,
+	CNSS_PCIE_REFCLKN,
+	CNSS_PCIE_RST,
+	CNSS_PCIE_WAKE,
+};
+
+struct cnss_pin_connect_result {
+	u32 fw_pwr_pin_result;
+	u32 fw_phy_io_pin_result;
+	u32 fw_rf_pin_result;
+	u32 host_pin_result;
+};
+
+enum cnss_debug_quirks {
+	LINK_DOWN_SELF_RECOVERY,
+	SKIP_DEVICE_BOOT,
+	USE_CORE_ONLY_FW,
+	SKIP_RECOVERY,
+	QMI_BYPASS,
+	ENABLE_WALTEST,
+	ENABLE_PCI_LINK_DOWN_PANIC,
+	FBC_BYPASS,
+	ENABLE_DAEMON_SUPPORT,
+	DISABLE_DRV,
+	DISABLE_IO_COHERENCY,
+	IGNORE_PCI_LINK_FAILURE,
+	DISABLE_TIME_SYNC,
+	FORCE_ONE_MSI,
+	QUIRK_MAX_VALUE
+};
+
+enum cnss_bdf_type {
+	CNSS_BDF_BIN,
+	CNSS_BDF_ELF,
+	CNSS_BDF_REGDB = 4,
+	CNSS_BDF_HDS = 6,
+};
+
+enum cnss_cal_status {
+	CNSS_CAL_DONE,
+	CNSS_CAL_TIMEOUT,
+	CNSS_CAL_FAILURE,
+};
+
+struct cnss_cal_info {
+	enum cnss_cal_status cal_status;
+};
+
+/**
+ * enum cnss_time_sync_period_vote - to get per vote time sync period
+ * @TIME_SYNC_VOTE_WLAN: WLAN Driver vote
+ * @TIME_SYNC_VOTE_CNSS: sys config vote
+ * @TIME_SYNC_VOTE_MAX
+ */
+enum cnss_time_sync_period_vote {
+	TIME_SYNC_VOTE_WLAN,
+	TIME_SYNC_VOTE_CNSS,
+	TIME_SYNC_VOTE_MAX,
+};
+
+struct cnss_control_params {
+	unsigned long quirks;
+	unsigned int mhi_timeout;
+	unsigned int mhi_m2_timeout;
+	unsigned int qmi_timeout;
+	unsigned int bdf_type;
+	unsigned int time_sync_period;
+	unsigned int time_sync_period_vote[TIME_SYNC_VOTE_MAX];
+};
+
+struct cnss_tcs_info {
+	resource_size_t cmd_base_addr;
+	void __iomem *cmd_base_addr_io;
+};
+
+struct cnss_cpr_info {
+	resource_size_t tcs_cmd_data_addr;
+	void __iomem *tcs_cmd_data_addr_io;
+	u32 cpr_pmic_addr;
+	u32 voltage;
+};
+
+enum cnss_ce_index {
+	CNSS_CE_00,
+	CNSS_CE_01,
+	CNSS_CE_02,
+	CNSS_CE_03,
+	CNSS_CE_04,
+	CNSS_CE_05,
+	CNSS_CE_06,
+	CNSS_CE_07,
+	CNSS_CE_08,
+	CNSS_CE_09,
+	CNSS_CE_10,
+	CNSS_CE_11,
+	CNSS_CE_COMMON,
+};
+
+struct cnss_dms_data {
+	u32 mac_valid;
+	u8 mac[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+
+enum cnss_timeout_type {
+	CNSS_TIMEOUT_QMI,
+	CNSS_TIMEOUT_POWER_UP,
+	CNSS_TIMEOUT_IDLE_RESTART,
+	CNSS_TIMEOUT_CALIBRATION,
+	CNSS_TIMEOUT_WLAN_WATCHDOG,
+	CNSS_TIMEOUT_RDDM,
+	CNSS_TIMEOUT_RECOVERY,
+	CNSS_TIMEOUT_DAEMON_CONNECTION,
+};
+
+struct cnss_sol_gpio {
+	int dev_sol_gpio;
+	int dev_sol_irq;
+	u32 dev_sol_counter;
+	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;
+	enum cnss_driver_mode driver_mode;
+	void *bus_priv;
+	enum cnss_dev_bus_type bus_type;
+	struct list_head vreg_list;
+	struct list_head clk_list;
+	struct cnss_pinctrl_info pinctrl_info;
+	struct cnss_sol_gpio sol_gpio;
+#if IS_ENABLED(CONFIG_MSM_SUBSYSTEM_RESTART)
+	struct cnss_subsys_info subsys_info;
+#endif
+	struct cnss_ramdump_info ramdump_info;
+	struct cnss_ramdump_info_v2 ramdump_info_v2;
+#if IS_ENABLED(CONFIG_ESOC)
+	struct cnss_esoc_info esoc_info;
+#endif
+	struct cnss_interconnect_cfg icc;
+	struct notifier_block modem_nb;
+	struct notifier_block reboot_nb;
+	struct notifier_block panic_nb;
+	struct cnss_platform_cap cap;
+	struct pm_qos_request qos_request;
+	struct cnss_device_version device_version;
+	u32 rc_num;
+	unsigned long device_id;
+	enum cnss_driver_status driver_status;
+	u32 recovery_count;
+	u8 recovery_enabled;
+	u8 recovery_pcss_enabled;
+	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;
+	struct work_struct recovery_work;
+	struct delayed_work wlan_reg_driver_work;
+	struct qmi_handle qmi_wlfw;
+	struct qmi_handle qmi_dms;
+	struct wlfw_rf_chip_info chip_info;
+	struct wlfw_rf_board_info board_info;
+	struct wlfw_soc_info soc_info;
+	struct wlfw_fw_version_info fw_version_info;
+	struct cnss_dev_mem_info dev_mem_info[CNSS_MAX_DEV_MEM_NUM];
+	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_V01];
+	struct cnss_fw_mem m3_mem;
+	struct cnss_fw_mem tme_lite_mem;
+	struct cnss_fw_mem tme_opt_file_mem[QMI_WLFW_MAX_TME_OPT_FILE_NUM];
+	struct cnss_fw_mem *cal_mem;
+	struct cnss_fw_mem aux_mem;
+	u64 cal_time;
+	bool cbc_file_download;
+	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_V01];
+	u32 *qdss_reg;
+	struct cnss_pin_connect_result pin_result;
+	struct dentry *root_dentry;
+	atomic_t pm_count;
+	struct timer_list fw_boot_timer;
+	struct completion power_up_complete;
+	struct completion cal_complete;
+	struct mutex dev_lock; /* mutex for register access through debugfs */
+	struct mutex driver_ops_lock; /* mutex for external driver ops */
+	struct cnss_wlan_driver *driver_ops;
+	u32 supported_link_speed;
+	u32 device_freq_hz;
+	u32 diag_reg_read_addr;
+	u32 diag_reg_read_mem_type;
+	u32 diag_reg_read_len;
+	u8 *diag_reg_read_buf;
+	u8 cal_done;
+	u8 powered_on;
+	u8 use_fw_path_with_prefix;
+	char firmware_name[MAX_FIRMWARE_NAME_LEN];
+	char fw_fallback_name[MAX_FIRMWARE_NAME_LEN];
+#ifndef CONFIG_DISABLE_CNSS_SRAM_DUMP
+	u8 *sram_dump;
+#endif
+	struct completion rddm_complete;
+	struct completion recovery_complete;
+	struct cnss_control_params ctrl_params;
+	struct cnss_cpr_info cpr_info;
+	u64 antenna;
+	u64 grant;
+	struct qmi_handle coex_qmi;
+	struct qmi_handle ims_qmi;
+	struct qmi_txn txn;
+	struct wakeup_source *recovery_ws;
+	u64 dynamic_feature;
+	void *get_info_cb_ctx;
+	int (*get_info_cb)(void *ctx, void *event, int event_len);
+	void *get_driver_async_data_ctx;
+	int (*get_driver_async_data_cb)(void *ctx, uint16_t type, void *event, int event_len);
+	bool cbc_enabled;
+	u8 use_pm_domain;
+	u8 use_nv_mac;
+	u8 set_wlaon_pwr_ctrl;
+	struct cnss_tcs_info tcs_info;
+	bool fw_pcie_gen_switch;
+	bool fw_aux_uc_support;
+	u64 fw_caps;
+	u8 pcie_gen_speed;
+	struct iommu_domain *audio_iommu_domain;
+	bool is_audio_shared_iommu_group;
+	struct cnss_dms_data dms;
+	int power_up_error;
+	u32 hw_trc_override;
+	u8 charger_mode;
+	struct mbox_client mbox_client_data;
+	struct mbox_chan *mbox_chan;
+	struct qmp *qmp;
+	const char *vreg_ol_cpr, *vreg_ipa;
+	const char **pdc_init_table, **vreg_pdc_map, **pmu_vreg_map;
+	int pdc_init_table_len, vreg_pdc_map_len, pmu_vreg_map_len;
+	bool adsp_pc_enabled;
+	u64 feature_list;
+	u32 dt_type;
+	struct kobject *wifi_kobj;
+	u16 hang_event_data_len;
+	u32 hang_data_addr_offset;
+	/* bitmap to detect FEM combination */
+	u8 hwid_bitmap;
+	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;
+	bool no_bwscale;
+	bool sleep_clk;
+	struct wlchip_serial_id_v01 serial_id;
+	bool ipa_shared_cb_enable;
+	u32 pcie_switch_type;
+};
+
+#if IS_ENABLED(CONFIG_ARCH_QCOM)
+static inline u64 cnss_get_host_timestamp(struct cnss_plat_data *plat_priv)
+{
+	u64 ticks = __arch_counter_get_cntvct();
+
+	do_div(ticks, TIME_CLOCK_FREQ_HZ / 100000);
+
+	return ticks * 10;
+}
+#else
+static inline u64 cnss_get_host_timestamp(struct cnss_plat_data *plat_priv)
+{
+	struct timespec64 ts;
+
+	ktime_get_ts64(&ts);
+
+	return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
+}
+#endif
+
+int cnss_wlan_hw_disable_check(struct cnss_plat_data *plat_priv);
+int cnss_wlan_hw_enable(void);
+struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev);
+struct cnss_plat_data *cnss_get_first_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_max_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);
+void cnss_get_sleep_clk_supported(struct cnss_plat_data *plat_priv);
+void cnss_get_bwscal_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);
+int cnss_get_vreg_type(struct cnss_plat_data *plat_priv,
+		       enum cnss_vreg_type type);
+void cnss_put_vreg_type(struct cnss_plat_data *plat_priv,
+			enum cnss_vreg_type type);
+int cnss_vreg_on_type(struct cnss_plat_data *plat_priv,
+		      enum cnss_vreg_type type);
+int cnss_vreg_off_type(struct cnss_plat_data *plat_priv,
+		       enum cnss_vreg_type type);
+int cnss_get_clk(struct cnss_plat_data *plat_priv);
+void cnss_put_clk(struct cnss_plat_data *plat_priv);
+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, 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);
+int cnss_disable_dev_sol_irq(struct cnss_plat_data *plat_priv);
+int cnss_get_dev_sol_value(struct cnss_plat_data *plat_priv);
+int cnss_init_dev_sol_irq(struct cnss_plat_data *plat_priv);
+int cnss_deinit_dev_sol_irq(struct cnss_plat_data *plat_priv);
+int cnss_set_host_sol_value(struct cnss_plat_data *plat_priv, int value);
+int cnss_get_host_sol_value(struct cnss_plat_data *plat_priv);
+int cnss_register_subsys(struct cnss_plat_data *plat_priv);
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_do_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_do_elf_ramdump(struct cnss_plat_data *plat_priv);
+int cnss_do_host_ramdump(struct cnss_plat_data *plat_priv,
+			 struct cnss_ssr_driver_dump_entry *ssr_entry,
+			 size_t num_entries_loaded);
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
+int cnss_get_cpr_info(struct cnss_plat_data *plat_priv);
+int cnss_update_cpr_info(struct cnss_plat_data *plat_priv);
+int cnss_va_to_pa(struct device *dev, size_t size, void *va, dma_addr_t dma,
+		  phys_addr_t *pa, unsigned long attrs);
+int cnss_minidump_add_region(struct cnss_plat_data *plat_priv,
+			     enum cnss_fw_dump_type type, int seg_no,
+			     void *va, phys_addr_t pa, size_t size);
+int cnss_minidump_remove_region(struct cnss_plat_data *plat_priv,
+				enum cnss_fw_dump_type type, int seg_no,
+				void *va, phys_addr_t pa, size_t size);
+int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv);
+int cnss_get_tcs_info(struct cnss_plat_data *plat_priv);
+unsigned int cnss_get_timeout(struct cnss_plat_data *plat_priv,
+			      enum cnss_timeout_type);
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv);
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv);
+int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv);
+int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *msg);
+void cnss_power_misc_params_init(struct cnss_plat_data *plat_priv);
+void cnss_pci_of_switch_type_init(struct cnss_plat_data *plat_priv);
+int cnss_aop_ol_cpr_cfg_setup(struct cnss_plat_data *plat_priv,
+			      struct wlfw_pmu_cfg_v01 *fw_pmu_cfg);
+int cnss_request_firmware_direct(struct cnss_plat_data *plat_priv,
+				 const struct firmware **fw_entry,
+				 const char *filename);
+int cnss_set_feature_list(struct cnss_plat_data *plat_priv,
+			  enum cnss_feature_v01 feature);
+int cnss_clear_feature_list(struct cnss_plat_data *plat_priv,
+			    enum cnss_feature_v01 feature);
+int cnss_get_feature_list(struct cnss_plat_data *plat_priv,
+			  u64 *feature_list);
+int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num);
+bool cnss_check_driver_loading_allowed(void);
+int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv);
+void cnss_recovery_handler(struct cnss_plat_data *plat_priv);
+size_t cnss_get_platform_name(struct cnss_plat_data *plat_priv,
+			      char *buf, const size_t buf_len);
+int cnss_iommu_map(struct iommu_domain *domain, unsigned long iova,
+		   phys_addr_t paddr, size_t size, int prot);
+int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv);
+int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv, bool state);
+#endif /* _CNSS_MAIN_H */

+ 12 - 0
qcom/opensource/wlan/platform/cnss2/niobe_consolidate_defconfig

@@ -0,0 +1,12 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS2_DEBUG=y

+ 11 - 0
qcom/opensource/wlan/platform/cnss2/niobe_gki_defconfig

@@ -0,0 +1,11 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 7913 - 0
qcom/opensource/wlan/platform/cnss2/pci.c

@@ -0,0 +1,7913 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include "main.h"
+#include "bus.h"
+#include "debug.h"
+#include "pci.h"
+#include "pci_platform.h"
+#include "reg.h"
+
+#define PCI_LINK_UP			1
+#define PCI_LINK_DOWN			0
+
+#define SAVE_PCI_CONFIG_SPACE		1
+#define RESTORE_PCI_CONFIG_SPACE	0
+
+#define PCI_BAR_NUM			0
+#define PCI_INVALID_READ(val)		((val) == U32_MAX)
+
+#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 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/"
+#define DEFAULT_PHY_M3_FILE_NAME	"m3.bin"
+#define DEFAULT_AUX_FILE_NAME		"aux_ucode.elf"
+#define DEFAULT_PHY_UCODE_FILE_NAME	"phy_ucode.elf"
+#define TME_PATCH_FILE_NAME_1_0		"tmel_peach_10.elf"
+#define TME_PATCH_FILE_NAME_2_0		"tmel_peach_20.elf"
+#define PHY_UCODE_V2_FILE_NAME		"phy_ucode20.elf"
+#define DEFAULT_FW_FILE_NAME		"amss.bin"
+#define FW_V2_FILE_NAME			"amss20.bin"
+#define DEFAULT_GENOA_FW_FTM_NAME	"genoaftm.bin"
+#define DEVICE_MAJOR_VERSION_MASK	0xF
+
+#define WAKE_MSI_NAME			"WAKE"
+
+#define DEV_RDDM_TIMEOUT		5000
+#define WAKE_EVENT_TIMEOUT		5000
+
+#ifdef CONFIG_CNSS_EMULATION
+#define EMULATION_HW			1
+#else
+#define EMULATION_HW			0
+#endif
+
+#define RAMDUMP_SIZE_DEFAULT		0x420000
+#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);
+
+#define MHI_TIMEOUT_OVERWRITE_MS	(plat_priv->ctrl_params.mhi_timeout)
+#define MHI_M2_TIMEOUT_MS		(plat_priv->ctrl_params.mhi_m2_timeout)
+
+#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US	1000
+#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US	2000
+
+#define RDDM_LINK_RECOVERY_RETRY		20
+#define RDDM_LINK_RECOVERY_RETRY_DELAY_MS	20
+
+#define FORCE_WAKE_DELAY_MIN_US			4000
+#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
+
+#define BOOT_DEBUG_TIMEOUT_MS			7000
+
+#define HANG_DATA_LENGTH		384
+#define HST_HANG_DATA_OFFSET		((3 * 1024 * 1024) - HANG_DATA_LENGTH)
+#define HSP_HANG_DATA_OFFSET		((2 * 1024 * 1024) - HANG_DATA_LENGTH)
+#define GNO_HANG_DATA_OFFSET		(0x7d000 - HANG_DATA_LENGTH)
+
+#define AFC_SLOT_SIZE                   0x1000
+#define AFC_MAX_SLOT                    2
+#define AFC_MEM_SIZE                    (AFC_SLOT_SIZE * AFC_MAX_SLOT)
+#define AFC_AUTH_STATUS_OFFSET          1
+#define AFC_AUTH_SUCCESS                1
+#define AFC_AUTH_ERROR                  0
+
+static const struct mhi_channel_config cnss_mhi_channels[] = {
+	{
+		.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 = 20,
+		.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 = 21,
+		.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,
+	},
+/* All MHI satellite config to be at the end of data struct */
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	{
+		.num = 50,
+		.name = "ADSP_0",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 51,
+		.name = "ADSP_1",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 70,
+		.name = "ADSP_2",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 71,
+		.name = "ADSP_3",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+#endif
+};
+
+static const struct mhi_channel_config cnss_mhi_channels_no_diag[] = {
+	{
+		.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 = 20,
+		.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 = 21,
+		.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,
+	},
+/* All MHI satellite config to be at the end of data struct */
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	{
+		.num = 50,
+		.name = "ADSP_0",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 51,
+		.name = "ADSP_1",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 70,
+		.name = "ADSP_2",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+	{
+		.num = 71,
+		.name = "ADSP_3",
+		.num_elements = 64,
+		.event_ring = 3,
+		.dir = DMA_BIDIRECTIONAL,
+		.ee_mask = 0x4,
+		.pollcfg = 0,
+		.doorbell = MHI_DB_BRST_DISABLE,
+		.lpm_notify = false,
+		.offload_channel = true,
+		.doorbell_mode_switch = false,
+		.auto_queue = false,
+	},
+#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
+static const struct mhi_event_config cnss_mhi_events[] = {
+#endif
+	{
+		.num_elements = 32,
+		.irq_moderation_ms = 0,
+		.irq = 1,
+		.mode = MHI_DB_BRST_DISABLE,
+		.data_type = MHI_ER_CTRL,
+		.priority = 0,
+		.hardware_event = false,
+		.client_managed = false,
+		.offload_channel = false,
+	},
+	{
+		.num_elements = 256,
+		.irq_moderation_ms = 0,
+		.irq = 2,
+		.mode = MHI_DB_BRST_DISABLE,
+		.priority = 1,
+		.hardware_event = false,
+		.client_managed = false,
+		.offload_channel = false,
+	},
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
+	{
+		.num_elements = 32,
+		.irq_moderation_ms = 0,
+		.irq = 1,
+		.mode = MHI_DB_BRST_DISABLE,
+		.data_type = MHI_ER_BW_SCALE,
+		.priority = 2,
+		.hardware_event = false,
+		.client_managed = false,
+		.offload_channel = false,
+	},
+#endif
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	{
+		.num_elements = 256,
+		.irq_moderation_ms = 0,
+		.irq = 2,
+		.mode = MHI_DB_BRST_DISABLE,
+		.data_type = MHI_ER_DATA,
+		.priority = 1,
+		.hardware_event = false,
+		.client_managed = true,
+		.offload_channel = true,
+	},
+#endif
+};
+
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+#define CNSS_MHI_SATELLITE_CH_CFG_COUNT 4
+#define CNSS_MHI_SATELLITE_EVT_COUNT 1
+#else
+#define CNSS_MHI_SATELLITE_CH_CFG_COUNT 0
+#define CNSS_MHI_SATELLITE_EVT_COUNT 0
+#endif
+
+static const struct mhi_controller_config cnss_mhi_config_no_diag = {
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	.max_channels = 72,
+#else
+	.max_channels = 32,
+#endif
+	.timeout_ms = 10000,
+	.use_bounce_buf = false,
+	.buf_len = 0x8000,
+	.num_channels = ARRAY_SIZE(cnss_mhi_channels_no_diag),
+	.ch_cfg = cnss_mhi_channels_no_diag,
+	.num_events = ARRAY_SIZE(cnss_mhi_events),
+	.event_cfg = cnss_mhi_events,
+	.m2_no_db = true,
+};
+
+static const struct mhi_controller_config cnss_mhi_config_default = {
+#if IS_ENABLED(CONFIG_MHI_SATELLITE)
+	.max_channels = 72,
+#else
+	.max_channels = 32,
+#endif
+	.timeout_ms = 10000,
+	.use_bounce_buf = false,
+	.buf_len = 0x8000,
+	.num_channels = ARRAY_SIZE(cnss_mhi_channels),
+	.ch_cfg = cnss_mhi_channels,
+	.num_events = ARRAY_SIZE(cnss_mhi_events),
+	.event_cfg = cnss_mhi_events,
+	.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,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
+	.bhie_offset = 0x0324,
+#endif
+};
+
+static const struct mhi_controller_config cnss_mhi_config_no_satellite = {
+	.max_channels = 32,
+	.timeout_ms = 10000,
+	.use_bounce_buf = false,
+	.buf_len = 0x8000,
+	.num_channels = ARRAY_SIZE(cnss_mhi_channels) -
+			CNSS_MHI_SATELLITE_CH_CFG_COUNT,
+	.ch_cfg = cnss_mhi_channels,
+	.num_events = ARRAY_SIZE(cnss_mhi_events) -
+			CNSS_MHI_SATELLITE_EVT_COUNT,
+	.event_cfg = cnss_mhi_events,
+	.m2_no_db = true,
+};
+
+static struct cnss_pci_reg ce_src[] = {
+	{ "SRC_RING_BASE_LSB", CE_SRC_RING_BASE_LSB_OFFSET },
+	{ "SRC_RING_BASE_MSB", CE_SRC_RING_BASE_MSB_OFFSET },
+	{ "SRC_RING_ID", CE_SRC_RING_ID_OFFSET },
+	{ "SRC_RING_MISC", CE_SRC_RING_MISC_OFFSET },
+	{ "SRC_CTRL", CE_SRC_CTRL_OFFSET },
+	{ "SRC_R0_CE_CH_SRC_IS", CE_SRC_R0_CE_CH_SRC_IS_OFFSET },
+	{ "SRC_RING_HP", CE_SRC_RING_HP_OFFSET },
+	{ "SRC_RING_TP", CE_SRC_RING_TP_OFFSET },
+	{ NULL },
+};
+
+static struct cnss_pci_reg ce_dst[] = {
+	{ "DEST_RING_BASE_LSB", CE_DEST_RING_BASE_LSB_OFFSET },
+	{ "DEST_RING_BASE_MSB", CE_DEST_RING_BASE_MSB_OFFSET },
+	{ "DEST_RING_ID", CE_DEST_RING_ID_OFFSET },
+	{ "DEST_RING_MISC", CE_DEST_RING_MISC_OFFSET },
+	{ "DEST_CTRL", CE_DEST_CTRL_OFFSET },
+	{ "CE_CH_DST_IS", CE_CH_DST_IS_OFFSET },
+	{ "CE_CH_DEST_CTRL2", CE_CH_DEST_CTRL2_OFFSET },
+	{ "DEST_RING_HP", CE_DEST_RING_HP_OFFSET },
+	{ "DEST_RING_TP", CE_DEST_RING_TP_OFFSET },
+	{ "STATUS_RING_BASE_LSB", CE_STATUS_RING_BASE_LSB_OFFSET },
+	{ "STATUS_RING_BASE_MSB", CE_STATUS_RING_BASE_MSB_OFFSET },
+	{ "STATUS_RING_ID", CE_STATUS_RING_ID_OFFSET },
+	{ "STATUS_RING_MISC", CE_STATUS_RING_MISC_OFFSET },
+	{ "STATUS_RING_HP", CE_STATUS_RING_HP_OFFSET },
+	{ "STATUS_RING_TP", CE_STATUS_RING_TP_OFFSET },
+	{ NULL },
+};
+
+static struct cnss_pci_reg ce_cmn[] = {
+	{ "GXI_ERR_INTS", CE_COMMON_GXI_ERR_INTS },
+	{ "GXI_ERR_STATS", CE_COMMON_GXI_ERR_STATS },
+	{ "GXI_WDOG_STATUS", CE_COMMON_GXI_WDOG_STATUS },
+	{ "TARGET_IE_0", CE_COMMON_TARGET_IE_0 },
+	{ "TARGET_IE_1", CE_COMMON_TARGET_IE_1 },
+	{ NULL },
+};
+
+static struct cnss_pci_reg qdss_csr[] = {
+	{ "QDSSCSR_ETRIRQCTRL", QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET },
+	{ "QDSSCSR_PRESERVEETF", QDSS_APB_DEC_CSR_PRESERVEETF_OFFSET },
+	{ "QDSSCSR_PRESERVEETR0", QDSS_APB_DEC_CSR_PRESERVEETR0_OFFSET },
+	{ "QDSSCSR_PRESERVEETR1", QDSS_APB_DEC_CSR_PRESERVEETR1_OFFSET },
+	{ NULL },
+};
+
+static struct cnss_pci_reg pci_scratch[] = {
+	{ "PCIE_SCRATCH_0", PCIE_SCRATCH_0_SOC_PCIE_REG },
+	{ "PCIE_SCRATCH_1", PCIE_SCRATCH_1_SOC_PCIE_REG },
+	{ "PCIE_SCRATCH_2", PCIE_SCRATCH_2_SOC_PCIE_REG },
+	{ NULL },
+};
+
+static struct cnss_pci_reg pci_bhi_debug[] = {
+	{ "PCIE_BHIE_DEBUG_0", PCIE_PCIE_BHIE_DEBUG_0 },
+	{ "PCIE_BHIE_DEBUG_1", PCIE_PCIE_BHIE_DEBUG_1 },
+	{ "PCIE_BHIE_DEBUG_2", PCIE_PCIE_BHIE_DEBUG_2 },
+	{ "PCIE_BHIE_DEBUG_3", PCIE_PCIE_BHIE_DEBUG_3 },
+	{ "PCIE_BHIE_DEBUG_4", PCIE_PCIE_BHIE_DEBUG_4 },
+	{ "PCIE_BHIE_DEBUG_5", PCIE_PCIE_BHIE_DEBUG_5 },
+	{ "PCIE_BHIE_DEBUG_6", PCIE_PCIE_BHIE_DEBUG_6 },
+	{ "PCIE_BHIE_DEBUG_7", PCIE_PCIE_BHIE_DEBUG_7 },
+	{ "PCIE_BHIE_DEBUG_8", PCIE_PCIE_BHIE_DEBUG_8 },
+	{ "PCIE_BHIE_DEBUG_9", PCIE_PCIE_BHIE_DEBUG_9 },
+	{ "PCIE_BHIE_DEBUG_10", PCIE_PCIE_BHIE_DEBUG_10 },
+	{ NULL },
+};
+
+/* First field of the structure is the device bit mask. Use
+ * enum cnss_pci_reg_mask as reference for the value.
+ */
+static struct cnss_misc_reg wcss_reg_access_seq[] = {
+	{1, 0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+	{1, 1, QCA6390_GCC_DEBUG_CLK_CTL, 0x802},
+	{1, 0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_PLL_MODE, 0},
+	{1, 1, QCA6390_GCC_DEBUG_CLK_CTL, 0x805},
+	{1, 0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+	{1, 0, QCA6390_WCSS_WFSS_PMM_WFSS_PMM_R0_PMM_CTRL, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_PMU_CX_CSR, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_AON_INT_RAW_STAT, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_AON_INT_EN, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_STS, 0},
+	{1, 1, QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_CTL, 0xD},
+	{1, 0, QCA6390_WCSS_PMM_TOP_TESTBUS_STS, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG, 0},
+	{1, 1, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG, 0},
+	{1, 1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x8},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_STS, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_CTL, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_0, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_9, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS0, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS1, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS2, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS3, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS4, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS5, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS6, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE0, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE1, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE2, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE3, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE4, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE5, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE6, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING0, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING1, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING2, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING3, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING4, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING5, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING6, 0},
+	{1, 1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x30040},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x30105},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+	{1, 0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+	{1, 0, QCA6390_WCSS_CC_WCSS_UMAC_NOC_CBCR, 0},
+	{1, 0, QCA6390_WCSS_CC_WCSS_UMAC_AHB_CBCR, 0},
+	{1, 0, QCA6390_WCSS_CC_WCSS_UMAC_GDSCR, 0},
+	{1, 0, QCA6390_WCSS_CC_WCSS_WLAN1_GDSCR, 0},
+	{1, 0, QCA6390_WCSS_CC_WCSS_WLAN2_GDSCR, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_PMM_INT_CLR, 0},
+	{1, 0, QCA6390_WCSS_PMM_TOP_AON_INT_STICKY_EN, 0},
+};
+
+static struct cnss_misc_reg pcie_reg_access_seq[] = {
+	{1, 0, QCA6390_PCIE_PCIE_WCSS_STATUS_FOR_DEBUG_LOW_PCIE_LOCAL_REG, 0},
+	{1, 0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+	{1, 1, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0x18},
+	{1, 0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+	{1, 0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+	{1, 0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_STATUS_SOC_PCIE_REG, 0},
+	{1, 0, QCA6390_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG, 0},
+	{1, 0, QCA6390_TLMM_GPIO_IN_OUT57, 0},
+	{1, 0, QCA6390_TLMM_GPIO_INTR_CFG57, 0},
+	{1, 0, QCA6390_TLMM_GPIO_INTR_STATUS57, 0},
+	{1, 0, QCA6390_TLMM_GPIO_IN_OUT59, 0},
+	{1, 0, QCA6390_TLMM_GPIO_INTR_CFG59, 0},
+	{1, 0, QCA6390_TLMM_GPIO_INTR_STATUS59, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_LTSSM, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_PM_STTS, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_PM_STTS_1, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_INT_STATUS, 0},
+	{1, 0, QCA6390_PCIE_PCIE_INT_ALL_STATUS, 0},
+	{1, 0, QCA6390_PCIE_PCIE_INT_ALL_MASK, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_BDF_TO_SID_CFG, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_3, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_MHI_CLOCK_RESET_CTRL, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_MHI_BASE_ADDR_LOWER, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_STATUS, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_CFG, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1SUB, 0},
+	{1, 0, QCA6390_PCIE_PCIE_CORE_CONFIG, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L2, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L1, 0},
+	{1, 0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2, 0},
+	{1, 0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_HIGH, 0},
+	{1, 0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_LOW, 0},
+	{1, 0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_HIGH, 0},
+	{1, 0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_LOW, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_STATUS_REG2, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_STATUS_REG2, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN2_CFG_REG1, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN1_CFG_REG1, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_APS_STATUS_REG1, 0},
+	{1, 0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_APS_STATUS_REG1, 0},
+	{1, 0, QCA6390_PCIE_PCIE_BHI_EXECENV_REG, 0},
+};
+
+static struct cnss_misc_reg wlaon_reg_access_seq[] = {
+	{3, 0, WLAON_SOC_POWER_CTRL, 0},
+	{3, 0, WLAON_SOC_PWR_WDG_BARK_THRSHD, 0},
+	{3, 0, WLAON_SOC_PWR_WDG_BITE_THRSHD, 0},
+	{3, 0, WLAON_SW_COLD_RESET, 0},
+	{3, 0, WLAON_RFA_MEM_SLP_NRET_N_OVERRIDE, 0},
+	{3, 0, WLAON_GDSC_DELAY_SETTING, 0},
+	{3, 0, WLAON_GDSC_DELAY_SETTING2, 0},
+	{3, 0, WLAON_WL_PWR_STATUS_REG, 0},
+	{3, 0, WLAON_WL_AON_DBG_CFG_REG, 0},
+	{2, 0, WLAON_WL_AON_DBG_ENABLE_GRP0_REG, 0},
+	{2, 0, WLAON_WL_AON_DBG_ENABLE_GRP1_REG, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL0, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL1, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL2, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL3, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL4, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL5, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL5_1, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL6, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL6_1, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL7, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL8, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL8_1, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL9, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL9_1, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL10, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL11, 0},
+	{2, 0, WLAON_WL_AON_APM_CFG_CTRL12, 0},
+	{2, 0, WLAON_WL_AON_APM_OVERRIDE_REG, 0},
+	{2, 0, WLAON_WL_AON_CXPC_REG, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS0, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS1, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS2, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS3, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS4, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS5, 0},
+	{2, 0, WLAON_WL_AON_APM_STATUS6, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL1, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL6, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL7, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL3, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL4, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL5, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL8, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL2, 0},
+	{3, 0, WLAON_GLOBAL_COUNTER_CTRL9, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL1, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL2, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL3, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL4, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL5, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL6, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL7, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL8, 0},
+	{3, 0, WLAON_RTC_CLK_CAL_CTRL9, 0},
+	{3, 0, WLAON_WCSSAON_CONFIG_REG, 0},
+	{3, 0, WLAON_WLAN_OEM_DEBUG_REG, 0},
+	{3, 0, WLAON_WLAN_RAM_DUMP_REG, 0},
+	{3, 0, WLAON_QDSS_WCSS_REG, 0},
+	{3, 0, WLAON_QDSS_WCSS_ACK, 0},
+	{3, 0, WLAON_WL_CLK_CNTL_KDF_REG, 0},
+	{3, 0, WLAON_WL_CLK_CNTL_PMU_HFRC_REG, 0},
+	{3, 0, WLAON_QFPROM_PWR_CTRL_REG, 0},
+	{3, 0, WLAON_DLY_CONFIG, 0},
+	{3, 0, WLAON_WLAON_Q6_IRQ_REG, 0},
+	{3, 0, WLAON_PCIE_INTF_SW_CFG_REG, 0},
+	{3, 0, WLAON_PCIE_INTF_STICKY_SW_CFG_REG, 0},
+	{3, 0, WLAON_PCIE_INTF_PHY_SW_CFG_REG, 0},
+	{3, 0, WLAON_PCIE_INTF_PHY_NOCSR_SW_CFG_REG, 0},
+	{3, 0, WLAON_Q6_COOKIE_BIT, 0},
+	{3, 0, WLAON_WARM_SW_ENTRY, 0},
+	{3, 0, WLAON_RESET_DBG_SW_ENTRY, 0},
+	{3, 0, WLAON_WL_PMUNOC_CFG_REG, 0},
+	{3, 0, WLAON_RESET_CAUSE_CFG_REG, 0},
+	{3, 0, WLAON_SOC_WCSSAON_WAKEUP_IRQ_7_EN_REG, 0},
+	{3, 0, WLAON_DEBUG, 0},
+	{3, 0, WLAON_SOC_PARAMETERS, 0},
+	{3, 0, WLAON_WLPM_SIGNAL, 0},
+	{3, 0, WLAON_SOC_RESET_CAUSE_REG, 0},
+	{3, 0, WLAON_WAKEUP_PCIE_SOC_REG, 0},
+	{3, 0, WLAON_PBL_STACK_CANARY, 0},
+	{3, 0, WLAON_MEM_TOT_NUM_GRP_REG, 0},
+	{3, 0, WLAON_MEM_TOT_BANKS_IN_GRP0_REG, 0},
+	{3, 0, WLAON_MEM_TOT_BANKS_IN_GRP1_REG, 0},
+	{3, 0, WLAON_MEM_TOT_BANKS_IN_GRP2_REG, 0},
+	{3, 0, WLAON_MEM_TOT_BANKS_IN_GRP3_REG, 0},
+	{3, 0, WLAON_MEM_TOT_SIZE_IN_GRP0_REG, 0},
+	{3, 0, WLAON_MEM_TOT_SIZE_IN_GRP1_REG, 0},
+	{3, 0, WLAON_MEM_TOT_SIZE_IN_GRP2_REG, 0},
+	{3, 0, WLAON_MEM_TOT_SIZE_IN_GRP3_REG, 0},
+	{3, 0, WLAON_MEM_SLP_NRET_OVERRIDE_GRP0_REG, 0},
+	{3, 0, WLAON_MEM_SLP_NRET_OVERRIDE_GRP1_REG, 0},
+	{3, 0, WLAON_MEM_SLP_NRET_OVERRIDE_GRP2_REG, 0},
+	{3, 0, WLAON_MEM_SLP_NRET_OVERRIDE_GRP3_REG, 0},
+	{3, 0, WLAON_MEM_SLP_RET_OVERRIDE_GRP0_REG, 0},
+	{3, 0, WLAON_MEM_SLP_RET_OVERRIDE_GRP1_REG, 0},
+	{3, 0, WLAON_MEM_SLP_RET_OVERRIDE_GRP2_REG, 0},
+	{3, 0, WLAON_MEM_SLP_RET_OVERRIDE_GRP3_REG, 0},
+	{3, 0, WLAON_MEM_CNT_SEL_REG, 0},
+	{3, 0, WLAON_MEM_NO_EXTBHS_REG, 0},
+	{3, 0, WLAON_MEM_DEBUG_REG, 0},
+	{3, 0, WLAON_MEM_DEBUG_BUS_REG, 0},
+	{3, 0, WLAON_MEM_REDUN_CFG_REG, 0},
+	{3, 0, WLAON_WL_AON_SPARE2, 0},
+	{3, 0, WLAON_VSEL_CFG_FOR_WL_RET_DISABLE_REG, 0},
+	{3, 0, WLAON_BTFM_WLAN_IPC_STATUS_REG, 0},
+	{3, 0, WLAON_MPM_COUNTER_CHICKEN_BITS, 0},
+	{3, 0, WLAON_WLPM_CHICKEN_BITS, 0},
+	{3, 0, WLAON_PCIE_PHY_PWR_REG, 0},
+	{3, 0, WLAON_WL_CLK_CNTL_PMU_LPO2M_REG, 0},
+	{3, 0, WLAON_WL_SS_ROOT_CLK_SWITCH_REG, 0},
+	{3, 0, WLAON_POWERCTRL_PMU_REG, 0},
+	{3, 0, WLAON_POWERCTRL_MEM_REG, 0},
+	{3, 0, WLAON_PCIE_PWR_CTRL_REG, 0},
+	{3, 0, WLAON_SOC_PWR_PROFILE_REG, 0},
+	{3, 0, WLAON_WCSSAON_PCIE_SR_STATUS_HI_REG, 0},
+	{3, 0, WLAON_WCSSAON_PCIE_SR_STATUS_LO_REG, 0},
+	{3, 0, WLAON_WCSS_TCSR_PMM_SR_STATUS_HI_REG, 0},
+	{3, 0, WLAON_WCSS_TCSR_PMM_SR_STATUS_LO_REG, 0},
+	{3, 0, WLAON_MEM_SVS_CFG_REG, 0},
+	{3, 0, WLAON_CMN_AON_MISC_REG, 0},
+	{3, 0, WLAON_INTR_STATUS, 0},
+	{2, 0, WLAON_INTR_ENABLE, 0},
+	{2, 0, WLAON_NOC_DBG_BUS_SEL_REG, 0},
+	{2, 0, WLAON_NOC_DBG_BUS_REG, 0},
+	{2, 0, WLAON_WL_CTRL_MISC_REG, 0},
+	{2, 0, WLAON_DBG_STATUS0, 0},
+	{2, 0, WLAON_DBG_STATUS1, 0},
+	{2, 0, WLAON_TIMERSYNC_OFFSET_L, 0},
+	{2, 0, WLAON_TIMERSYNC_OFFSET_H, 0},
+	{2, 0, WLAON_PMU_LDO_SETTLE_REG, 0},
+};
+
+static struct cnss_misc_reg syspm_reg_access_seq[] = {
+	{1, 0, QCA6390_SYSPM_SYSPM_PWR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_DBG_BTFM_AON_REG, 0},
+	{1, 0, QCA6390_SYSPM_DBG_BUS_SEL_REG, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+	{1, 0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+};
+
+static struct cnss_print_optimize print_optimize;
+
+#define WCSS_REG_SIZE ARRAY_SIZE(wcss_reg_access_seq)
+#define PCIE_REG_SIZE ARRAY_SIZE(pcie_reg_access_seq)
+#define WLAON_REG_SIZE ARRAY_SIZE(wlaon_reg_access_seq)
+#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);
+static void cnss_pci_update_link_event(struct cnss_pci_data *pci_priv,
+				       enum cnss_bus_event_type type,
+				       void *data);
+
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
+static void cnss_mhi_debug_reg_dump(struct cnss_pci_data *pci_priv)
+{
+	mhi_debug_reg_dump(pci_priv->mhi_ctrl);
+}
+
+static void cnss_mhi_dump_sfr(struct cnss_pci_data *pci_priv)
+{
+	mhi_dump_sfr(pci_priv->mhi_ctrl);
+}
+
+static bool cnss_mhi_scan_rddm_cookie(struct cnss_pci_data *pci_priv,
+				      u32 cookie)
+{
+	return mhi_scan_rddm_cookie(pci_priv->mhi_ctrl, cookie);
+}
+
+static int cnss_mhi_pm_fast_suspend(struct cnss_pci_data *pci_priv,
+				    bool notify_clients)
+{
+	return mhi_pm_fast_suspend(pci_priv->mhi_ctrl, notify_clients);
+}
+
+static int cnss_mhi_pm_fast_resume(struct cnss_pci_data *pci_priv,
+				   bool notify_clients)
+{
+	return mhi_pm_fast_resume(pci_priv->mhi_ctrl, notify_clients);
+}
+
+static void cnss_mhi_set_m2_timeout_ms(struct cnss_pci_data *pci_priv,
+				       u32 timeout)
+{
+	return mhi_set_m2_timeout_ms(pci_priv->mhi_ctrl, timeout);
+}
+
+static int cnss_mhi_device_get_sync_atomic(struct cnss_pci_data *pci_priv,
+					   int timeout_us, bool in_panic)
+{
+	return mhi_device_get_sync_atomic(pci_priv->mhi_ctrl->mhi_dev,
+					  timeout_us, in_panic);
+}
+
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+static int cnss_mhi_host_notify_db_disable_trace(struct cnss_pci_data *pci_priv)
+{
+	return mhi_host_notify_db_disable_trace(pci_priv->mhi_ctrl);
+}
+#endif
+
+static void
+cnss_mhi_controller_set_bw_scale_cb(struct cnss_pci_data *pci_priv,
+				    int (*cb)(struct mhi_controller *mhi_ctrl,
+					      struct mhi_link_info *link_info))
+{
+	mhi_controller_set_bw_scale_cb(pci_priv->mhi_ctrl, cb);
+}
+
+static int cnss_mhi_force_reset(struct cnss_pci_data *pci_priv)
+{
+	return mhi_force_reset(pci_priv->mhi_ctrl);
+}
+
+void cnss_mhi_controller_set_base(struct cnss_pci_data *pci_priv,
+				  phys_addr_t base)
+{
+	return mhi_controller_set_base(pci_priv->mhi_ctrl, base);
+}
+#else
+static void cnss_mhi_debug_reg_dump(struct cnss_pci_data *pci_priv)
+{
+}
+
+static void cnss_mhi_dump_sfr(struct cnss_pci_data *pci_priv)
+{
+}
+
+static bool cnss_mhi_scan_rddm_cookie(struct cnss_pci_data *pci_priv,
+				      u32 cookie)
+{
+	return false;
+}
+
+static int cnss_mhi_pm_fast_suspend(struct cnss_pci_data *pci_priv,
+				    bool notify_clients)
+{
+	return -EOPNOTSUPP;
+}
+
+static int cnss_mhi_pm_fast_resume(struct cnss_pci_data *pci_priv,
+				   bool notify_clients)
+{
+	return -EOPNOTSUPP;
+}
+
+static void cnss_mhi_set_m2_timeout_ms(struct cnss_pci_data *pci_priv,
+				       u32 timeout)
+{
+}
+
+static int cnss_mhi_device_get_sync_atomic(struct cnss_pci_data *pci_priv,
+					   int timeout_us, bool in_panic)
+{
+	return -EOPNOTSUPP;
+}
+
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+static int cnss_mhi_host_notify_db_disable_trace(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+static void
+cnss_mhi_controller_set_bw_scale_cb(struct cnss_pci_data *pci_priv,
+				    int (*cb)(struct mhi_controller *mhi_ctrl,
+					      struct mhi_link_info *link_info))
+{
+}
+
+static int cnss_mhi_force_reset(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+void cnss_mhi_controller_set_base(struct cnss_pci_data *pci_priv,
+				  phys_addr_t base)
+{
+}
+#endif /* CONFIG_MHI_BUS_MISC */
+
+#ifdef CONFIG_CNSS2_SMMU_DB_SUPPORT
+#define CNSS_MHI_WAKE_TIMEOUT		500000
+
+static void cnss_record_smmu_fault_timestamp(struct cnss_pci_data *pci_priv,
+					     enum cnss_smmu_fault_time id)
+{
+	if (id >= SMMU_CB_MAX)
+		return;
+
+	pci_priv->smmu_fault_timestamp[id] = sched_clock();
+}
+
+static void cnss_pci_smmu_fault_handler_irq(struct iommu_domain *domain,
+					    void *handler_token)
+{
+	struct cnss_pci_data *pci_priv = handler_token;
+	int ret = 0;
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_ENTRY);
+	ret = cnss_mhi_device_get_sync_atomic(pci_priv,
+					      CNSS_MHI_WAKE_TIMEOUT, true);
+	if (ret < 0) {
+		cnss_pr_err("Failed to bring mhi in M0 state, ret %d\n", ret);
+		return;
+	}
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_DOORBELL_RING);
+	ret = cnss_mhi_host_notify_db_disable_trace(pci_priv);
+	if (ret < 0)
+		cnss_pr_err("Fail to notify wlan fw to stop trace collection, ret %d\n", ret);
+
+	cnss_record_smmu_fault_timestamp(pci_priv, SMMU_CB_EXIT);
+}
+
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv)
+{
+	qcom_iommu_set_fault_handler_irq(pci_priv->iommu_domain,
+					 cnss_pci_smmu_fault_handler_irq, pci_priv);
+}
+#else
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+
+int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv)
+{
+	u16 device_id;
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
+		cnss_pr_dbg("%ps: PCIe link is in suspend state\n",
+			    (void *)_RET_IP_);
+		return -EACCES;
+	}
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_err("%ps: PCIe link is down\n", (void *)_RET_IP_);
+		return -EIO;
+	}
+
+	pci_read_config_word(pci_priv->pci_dev, PCI_DEVICE_ID, &device_id);
+	if (device_id != pci_priv->device_id)  {
+		cnss_fatal_err("%ps: PCI device ID mismatch, link possibly down, current read ID: 0x%x, record ID: 0x%x\n",
+			       (void *)_RET_IP_, device_id,
+			       pci_priv->device_id);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK;
+	u32 window_enable = WINDOW_ENABLE_BIT | window;
+	u32 val;
+
+	if (plat_priv->device_id == QCN7605_DEVICE_ID)
+		window_enable = QCN7605_WINDOW_ENABLE_BIT | window;
+
+	if (plat_priv->device_id == PEACH_DEVICE_ID) {
+		writel_relaxed(window_enable, pci_priv->bar +
+			       PEACH_PCIE_REMAP_BAR_CTRL_OFFSET);
+	} else {
+		writel_relaxed(window_enable, pci_priv->bar +
+			       QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET);
+	}
+
+	if (window != pci_priv->remap_window) {
+		pci_priv->remap_window = window;
+		cnss_pr_dbg("Config PCIe remap window register to 0x%x\n",
+			    window_enable);
+	}
+
+	/* Read it back to make sure the write has taken effect */
+	if (plat_priv->device_id == PEACH_DEVICE_ID) {
+		val = readl_relaxed(pci_priv->bar +
+			PEACH_PCIE_REMAP_BAR_CTRL_OFFSET);
+	} else {
+		val = readl_relaxed(pci_priv->bar +
+			QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET);
+	}
+	if (val != window_enable) {
+		cnss_pr_err("Failed to config window register to 0x%x, current value: 0x%x\n",
+			    window_enable, val);
+		if (!cnss_pci_check_link_status(pci_priv) &&
+		    !test_bit(CNSS_IN_PANIC, &plat_priv->driver_state))
+			CNSS_ASSERT(0);
+	}
+}
+
+static int cnss_pci_reg_read(struct cnss_pci_data *pci_priv,
+			     u32 offset, u32 *val)
+{
+	int ret;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (!in_interrupt() && !irqs_disabled()) {
+		ret = cnss_pci_check_link_status(pci_priv);
+		if (ret)
+			return ret;
+	}
+
+	if (pci_priv->pci_dev->device == QCA6174_DEVICE_ID ||
+	    offset < MAX_UNWINDOWED_ADDRESS) {
+		*val = readl_relaxed(pci_priv->bar + offset);
+		return 0;
+	}
+
+	/* If in panic, assumption is kernel panic handler will hold all threads
+	 * and interrupts. Further pci_reg_window_lock could be held before
+	 * panic. So only lock during normal operation.
+	 */
+	if (test_bit(CNSS_IN_PANIC, &plat_priv->driver_state)) {
+		cnss_pci_select_window(pci_priv, offset);
+		*val = readl_relaxed(pci_priv->bar + WINDOW_START +
+				     (offset & WINDOW_RANGE_MASK));
+	} else {
+		spin_lock_bh(&pci_reg_window_lock);
+		cnss_pci_select_window(pci_priv, offset);
+		*val = readl_relaxed(pci_priv->bar + WINDOW_START +
+				     (offset & WINDOW_RANGE_MASK));
+		spin_unlock_bh(&pci_reg_window_lock);
+	}
+
+	return 0;
+}
+
+static int cnss_pci_reg_write(struct cnss_pci_data *pci_priv, u32 offset,
+			      u32 val)
+{
+	int ret;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (!in_interrupt() && !irqs_disabled()) {
+		ret = cnss_pci_check_link_status(pci_priv);
+		if (ret)
+			return ret;
+	}
+
+	if (pci_priv->pci_dev->device == QCA6174_DEVICE_ID ||
+	    offset < MAX_UNWINDOWED_ADDRESS) {
+		writel_relaxed(val, pci_priv->bar + offset);
+		return 0;
+	}
+
+	/* Same constraint as PCI register read in panic */
+	if (test_bit(CNSS_IN_PANIC, &plat_priv->driver_state)) {
+		cnss_pci_select_window(pci_priv, offset);
+		writel_relaxed(val, pci_priv->bar + WINDOW_START +
+			  (offset & WINDOW_RANGE_MASK));
+	} else {
+		spin_lock_bh(&pci_reg_window_lock);
+		cnss_pci_select_window(pci_priv, offset);
+		writel_relaxed(val, pci_priv->bar + WINDOW_START +
+			  (offset & WINDOW_RANGE_MASK));
+		spin_unlock_bh(&pci_reg_window_lock);
+	}
+
+	return 0;
+}
+
+static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev = &pci_priv->pci_dev->dev;
+	int ret;
+
+	ret = cnss_pci_force_wake_request_sync(dev,
+					       FORCE_WAKE_DELAY_TIMEOUT_US);
+	if (ret) {
+		if (ret != -EAGAIN)
+			cnss_pr_err("Failed to request force wake\n");
+		return ret;
+	}
+
+	/* If device's M1 state-change event races here, it can be ignored,
+	 * as the device is expected to immediately move from M2 to M0
+	 * without entering low power state.
+	 */
+	if (cnss_pci_is_device_awake(dev) != true)
+		cnss_pr_warn("MHI not in M0, while reg still accessible\n");
+
+	return 0;
+}
+
+static int cnss_pci_force_wake_put(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev = &pci_priv->pci_dev->dev;
+	int ret;
+
+	ret = cnss_pci_force_wake_release(dev);
+	if (ret && ret != -EAGAIN)
+		cnss_pr_err("Failed to release force wake\n");
+
+	return ret;
+}
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+/**
+ * cnss_setup_bus_bandwidth() - Setup interconnect vote for given bandwidth
+ * @plat_priv: Platform private data struct
+ * @bw: bandwidth
+ * @save: toggle flag to save bandwidth to current_bw_vote
+ *
+ * Setup bandwidth votes for configured interconnect paths
+ *
+ * Return: 0 for success
+ */
+static int cnss_setup_bus_bandwidth(struct cnss_plat_data *plat_priv,
+				    u32 bw, bool save)
+{
+	int ret = 0;
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	if (!plat_priv->icc.path_count)
+		return -EOPNOTSUPP;
+
+	if (bw >= plat_priv->icc.bus_bw_cfg_count) {
+		cnss_pr_err("Invalid bus bandwidth Type: %d", bw);
+		return -EINVAL;
+	}
+
+	cnss_pr_buf("Bandwidth vote to %d, save %d\n", bw, save);
+
+	list_for_each_entry(bus_bw_info, &plat_priv->icc.list_head, list) {
+		ret = icc_set_bw(bus_bw_info->icc_path,
+				 bus_bw_info->cfg_table[bw].avg_bw,
+				 bus_bw_info->cfg_table[bw].peak_bw);
+		if (ret) {
+			cnss_pr_err("Could not set BW Cfg: %d, err = %d ICC Path: %s Val: %d %d\n",
+				    bw, ret, bus_bw_info->icc_name,
+				    bus_bw_info->cfg_table[bw].avg_bw,
+				    bus_bw_info->cfg_table[bw].peak_bw);
+			break;
+		}
+	}
+	if (ret == 0 && save)
+		plat_priv->icc.current_bw_vote = bw;
+	return ret;
+}
+
+int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (bandwidth < 0)
+		return -EINVAL;
+
+	return cnss_setup_bus_bandwidth(plat_priv, (u32)bandwidth, true);
+}
+#else
+static int cnss_setup_bus_bandwidth(struct cnss_plat_data *plat_priv,
+				    u32 bw, bool save)
+{
+	return 0;
+}
+
+int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	return 0;
+}
+#endif
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_pci_debug_reg_read(struct cnss_pci_data *pci_priv, u32 offset,
+			    u32 *val, bool raw_access)
+{
+	int ret = 0;
+	bool do_force_wake_put = true;
+
+	if (raw_access) {
+		ret = cnss_pci_reg_read(pci_priv, offset, val);
+		goto out;
+	}
+
+	ret = cnss_pci_is_device_down(&pci_priv->pci_dev->dev);
+	if (ret)
+		goto out;
+
+	ret = cnss_pci_pm_runtime_get_sync(pci_priv, RTPM_ID_CNSS);
+	if (ret < 0)
+		goto runtime_pm_put;
+
+	ret = cnss_pci_force_wake_get(pci_priv);
+	if (ret)
+		do_force_wake_put = false;
+
+	ret = cnss_pci_reg_read(pci_priv, offset, val);
+	if (ret) {
+		cnss_pr_err("Failed to read register offset 0x%x, err = %d\n",
+			    offset, ret);
+		goto force_wake_put;
+	}
+
+force_wake_put:
+	if (do_force_wake_put)
+		cnss_pci_force_wake_put(pci_priv);
+runtime_pm_put:
+	cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+	cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+out:
+	return ret;
+}
+
+int cnss_pci_debug_reg_write(struct cnss_pci_data *pci_priv, u32 offset,
+			     u32 val, bool raw_access)
+{
+	int ret = 0;
+	bool do_force_wake_put = true;
+
+	if (raw_access) {
+		ret = cnss_pci_reg_write(pci_priv, offset, val);
+		goto out;
+	}
+
+	ret = cnss_pci_is_device_down(&pci_priv->pci_dev->dev);
+	if (ret)
+		goto out;
+
+	ret = cnss_pci_pm_runtime_get_sync(pci_priv, RTPM_ID_CNSS);
+	if (ret < 0)
+		goto runtime_pm_put;
+
+	ret = cnss_pci_force_wake_get(pci_priv);
+	if (ret)
+		do_force_wake_put = false;
+
+	ret = cnss_pci_reg_write(pci_priv, offset, val);
+	if (ret) {
+		cnss_pr_err("Failed to write 0x%x to register offset 0x%x, err = %d\n",
+			    val, offset, ret);
+		goto force_wake_put;
+	}
+
+force_wake_put:
+	if (do_force_wake_put)
+		cnss_pci_force_wake_put(pci_priv);
+runtime_pm_put:
+	cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+	cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+out:
+	return ret;
+}
+
+static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	bool link_down_or_recovery;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	link_down_or_recovery = pci_priv->pci_link_down_ind ||
+		(test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state));
+
+	if (save) {
+		if (link_down_or_recovery) {
+			pci_priv->saved_state = NULL;
+		} else {
+			pci_save_state(pci_dev);
+			pci_priv->saved_state = pci_store_saved_state(pci_dev);
+		}
+	} else {
+		if (link_down_or_recovery) {
+			pci_load_saved_state(pci_dev, pci_priv->default_state);
+			pci_restore_state(pci_dev);
+		} else if (pci_priv->saved_state) {
+			pci_load_and_free_saved_state(pci_dev,
+						      &pci_priv->saved_state);
+			pci_restore_state(pci_dev);
+		}
+	}
+
+	return 0;
+}
+
+static int cnss_update_supported_link_info(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *root_port;
+	struct device_node *root_of_node;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -EINVAL;
+
+	if (pci_priv->device_id != KIWI_DEVICE_ID)
+		return ret;
+
+	plat_priv = pci_priv->plat_priv;
+	root_port = pcie_find_root_port(pci_priv->pci_dev);
+
+	if (!root_port) {
+		cnss_pr_err("PCIe root port is null\n");
+		return -EINVAL;
+	}
+
+	root_of_node = root_port->dev.of_node;
+	if (root_of_node && root_of_node->parent) {
+		ret = of_property_read_u32(root_of_node->parent,
+					   "qcom,target-link-speed",
+					   &plat_priv->supported_link_speed);
+		if (!ret)
+			cnss_pr_dbg("Supported PCIe Link Speed: %d\n",
+				    plat_priv->supported_link_speed);
+		else
+			plat_priv->supported_link_speed = 0;
+	}
+
+	return ret;
+}
+
+static int cnss_pci_get_link_status(struct cnss_pci_data *pci_priv)
+{
+	u16 link_status;
+	int ret;
+
+	ret = pcie_capability_read_word(pci_priv->pci_dev, PCI_EXP_LNKSTA,
+					&link_status);
+	if (ret)
+		return ret;
+
+	cnss_pr_dbg("Get PCI link status register: %u\n", link_status);
+
+	pci_priv->def_link_speed = link_status & PCI_EXP_LNKSTA_CLS;
+	pci_priv->def_link_width =
+		(link_status & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
+	pci_priv->cur_link_speed = pci_priv->def_link_speed;
+
+	cnss_pr_dbg("Default PCI link speed is 0x%x, link width is 0x%x\n",
+		    pci_priv->def_link_speed, pci_priv->def_link_width);
+
+	return 0;
+}
+
+static void cnss_pci_soc_scratch_reg_dump(struct cnss_pci_data *pci_priv)
+{
+	u32 reg_offset, val;
+	int i;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pr_dbg("Start to dump SOC Scratch registers\n");
+
+	for (i = 0; pci_scratch[i].name; i++) {
+		reg_offset = pci_scratch[i].offset;
+		if (cnss_pci_reg_read(pci_priv, reg_offset, &val))
+			return;
+		cnss_pr_dbg("PCIE_SOC_REG_%s = 0x%x\n",
+			    pci_scratch[i].name, val);
+	}
+}
+
+static void cnss_pci_soc_reset_cause_reg_dump(struct cnss_pci_data *pci_priv)
+{
+	u32 val;
+
+	switch (pci_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pr_dbg("Start to dump SOC Reset Cause registers\n");
+
+	if (cnss_pci_reg_read(pci_priv, WLAON_SOC_RESET_CAUSE_SHADOW_REG,
+			      &val))
+		return;
+	cnss_pr_dbg("WLAON_SOC_RESET_CAUSE_SHADOW_REG = 0x%x\n",
+		     val);
+
+}
+
+static void cnss_pci_bhi_debug_reg_dump(struct cnss_pci_data *pci_priv)
+{
+	u32 reg_offset, val;
+	int i;
+
+	switch (pci_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return;
+	}
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pr_dbg("Start to dump PCIE BHIE DEBUG registers\n");
+
+	for (i = 0; pci_bhi_debug[i].name; i++) {
+		reg_offset = pci_bhi_debug[i].offset;
+		if (cnss_pci_reg_read(pci_priv, reg_offset, &val))
+			return;
+		cnss_pr_dbg("PCIE__%s = 0x%x\n",
+			     pci_bhi_debug[i].name, val);
+	}
+}
+
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
+		cnss_pr_info("PCI link is already suspended\n");
+		goto out;
+	}
+
+	pci_clear_master(pci_priv->pci_dev);
+
+	ret = cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+	if (ret)
+		goto out;
+
+	pci_disable_device(pci_priv->pci_dev);
+
+	if (pci_priv->pci_dev->device != QCA6174_DEVICE_ID) {
+		ret = pci_set_power_state(pci_priv->pci_dev, PCI_D3hot);
+		if (ret)
+			cnss_pr_err("Failed to set D3Hot, err =  %d\n", ret);
+	}
+
+	/* Always do PCIe L2 suspend during power off/PCIe link recovery */
+	pci_priv->drv_connected_last = 0;
+
+	ret = cnss_set_pci_link(pci_priv, PCI_LINK_DOWN);
+	if (ret)
+		goto out;
+
+	pci_priv->pci_link_state = PCI_LINK_DOWN;
+
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	if (pci_priv->pci_link_state == PCI_LINK_UP) {
+		cnss_pr_info("PCI link is already resumed\n");
+		goto out;
+	}
+
+	ret = cnss_set_pci_link(pci_priv, PCI_LINK_UP);
+	if (ret) {
+		ret = -EAGAIN;
+		cnss_pci_update_link_event(pci_priv,
+					   BUS_EVENT_PCI_LINK_RESUME_FAIL, NULL);
+		goto out;
+	}
+
+	pci_priv->pci_link_state = PCI_LINK_UP;
+
+	if (pci_priv->pci_dev->device != QCA6174_DEVICE_ID) {
+		ret = pci_set_power_state(pci_priv->pci_dev, PCI_D0);
+		if (ret) {
+			cnss_pr_err("Failed to set D0, err = %d\n", ret);
+			goto out;
+		}
+	}
+
+	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;
+	}
+
+	pci_set_master(pci_priv->pci_dev);
+
+	if (pci_priv->pci_link_down_ind)
+		pci_priv->pci_link_down_ind = false;
+
+	return 0;
+out:
+	return ret;
+}
+
+static void cnss_pci_update_link_event(struct cnss_pci_data *pci_priv,
+				       enum cnss_bus_event_type type,
+				       void *data)
+{
+	struct cnss_bus_event bus_event;
+
+	bus_event.etype = type;
+	bus_event.event_data = data;
+	cnss_pci_call_driver_uevent(pci_priv, CNSS_BUS_EVENT, &bus_event);
+}
+
+void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	unsigned long flags;
+
+	if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC,
+		     &plat_priv->ctrl_params.quirks))
+		panic("cnss: PCI link is down\n");
+
+	spin_lock_irqsave(&pci_link_down_lock, flags);
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress, ignore\n");
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+		return;
+	}
+	pci_priv->pci_link_down_ind = true;
+	spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+	if (pci_priv->mhi_ctrl) {
+		/* Notify MHI about link down*/
+		mhi_report_error(pci_priv->mhi_ctrl);
+	}
+
+	if (pci_dev->device == QCA6174_DEVICE_ID)
+		disable_irq_nosync(pci_dev->irq);
+
+	/* Notify bus related event. Now for all supported chips.
+	 * Here PCIe LINK_DOWN notification taken care.
+	 * uevent buffer can be extended later, to cover more bus info.
+	 */
+	cnss_pci_update_link_event(pci_priv, BUS_EVENT_PCI_LINK_DOWN, NULL);
+
+	cnss_fatal_err("PCI link down, schedule recovery\n");
+	reinit_completion(&pci_priv->wake_event_complete);
+	cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
+}
+
+int cnss_pci_link_down(struct device *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 = NULL;
+	int ret;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -EINVAL;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is already in progress\n");
+		return -EBUSY;
+	}
+
+	if (pci_priv->drv_connected_last &&
+	    of_property_read_bool(plat_priv->plat_dev->dev.of_node,
+				  "cnss-enable-self-recovery"))
+		plat_priv->ctrl_params.quirks |= BIT(LINK_DOWN_SELF_RECOVERY);
+
+	cnss_pr_err("PCI link down is detected by drivers\n");
+
+	ret = cnss_pci_assert_perst(pci_priv);
+	if (ret)
+		cnss_pci_handle_linkdown(pci_priv);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_pci_link_down);
+
+int cnss_pci_get_reg_dump(struct device *dev, uint8_t *buffer, uint32_t len)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
+		cnss_pr_dbg("No PCIe reg dump since PCIe is suspended(D3)\n");
+		return -EACCES;
+	}
+
+	cnss_pr_dbg("Start to get PCIe reg dump\n");
+
+	return _cnss_pci_get_reg_dump(pci_priv, buffer, len);
+}
+EXPORT_SYMBOL(cnss_pci_get_reg_dump);
+
+int cnss_pcie_is_device_down(struct cnss_pci_data *pci_priv)
+{
+	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;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	return test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) |
+		pci_priv->pci_link_down_ind;
+}
+
+int cnss_pci_is_device_down(struct device *dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+	return cnss_pcie_is_device_down(pci_priv);
+}
+EXPORT_SYMBOL(cnss_pci_is_device_down);
+
+int cnss_pci_shutdown_cleanup(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	ret = del_timer(&pci_priv->dev_rddm_timer);
+	cnss_pr_dbg("%s RDDM timer deleted", ret ? "Active" : "Inactive");
+	return ret;
+}
+
+void cnss_pci_lock_reg_window(struct device *dev, unsigned long *flags)
+{
+	spin_lock_bh(&pci_reg_window_lock);
+}
+EXPORT_SYMBOL(cnss_pci_lock_reg_window);
+
+void cnss_pci_unlock_reg_window(struct device *dev, unsigned long *flags)
+{
+	spin_unlock_bh(&pci_reg_window_lock);
+}
+EXPORT_SYMBOL(cnss_pci_unlock_reg_window);
+
+int cnss_get_pci_slot(struct device *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 = NULL;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -EINVAL;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	return plat_priv->rc_num;
+}
+EXPORT_SYMBOL(cnss_get_pci_slot);
+
+/**
+ * cnss_pci_dump_bl_sram_mem - Dump WLAN device bootloader debug log
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * Dump primary and secondary bootloader debug log data. For SBL check the
+ * log struct address and size for validity.
+ *
+ * Return: None
+ */
+static void cnss_pci_dump_bl_sram_mem(struct cnss_pci_data *pci_priv)
+{
+	enum mhi_ee_type ee;
+	u32 mem_addr, val, pbl_log_max_size, sbl_log_max_size;
+	u32 pbl_log_sram_start;
+	u32 pbl_stage, sbl_log_start, sbl_log_size;
+	u32 pbl_wlan_boot_cfg, pbl_bootstrap_status;
+	u32 pbl_bootstrap_status_reg = PBL_BOOTSTRAP_STATUS;
+	u32 sbl_log_def_start = SRAM_START;
+	u32 sbl_log_def_end = SRAM_END;
+	int i;
+
+	cnss_pci_soc_reset_cause_reg_dump(pci_priv);
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+		pbl_log_sram_start = QCA6390_DEBUG_PBL_LOG_SRAM_START;
+		pbl_log_max_size = QCA6390_DEBUG_PBL_LOG_SRAM_MAX_SIZE;
+		sbl_log_max_size = QCA6390_DEBUG_SBL_LOG_SRAM_MAX_SIZE;
+		break;
+	case QCA6490_DEVICE_ID:
+		pbl_log_sram_start = QCA6490_DEBUG_PBL_LOG_SRAM_START;
+		pbl_log_max_size = QCA6490_DEBUG_PBL_LOG_SRAM_MAX_SIZE;
+		sbl_log_max_size = QCA6490_DEBUG_SBL_LOG_SRAM_MAX_SIZE;
+		break;
+	case KIWI_DEVICE_ID:
+		pbl_bootstrap_status_reg = KIWI_PBL_BOOTSTRAP_STATUS;
+		pbl_log_sram_start = KIWI_DEBUG_PBL_LOG_SRAM_START;
+		pbl_log_max_size = KIWI_DEBUG_PBL_LOG_SRAM_MAX_SIZE;
+		sbl_log_max_size = KIWI_DEBUG_SBL_LOG_SRAM_MAX_SIZE;
+		break;
+	case MANGO_DEVICE_ID:
+		pbl_bootstrap_status_reg = MANGO_PBL_BOOTSTRAP_STATUS;
+		pbl_log_sram_start = MANGO_DEBUG_PBL_LOG_SRAM_START;
+		pbl_log_max_size = MANGO_DEBUG_PBL_LOG_SRAM_MAX_SIZE;
+		sbl_log_max_size = MANGO_DEBUG_SBL_LOG_SRAM_MAX_SIZE;
+		break;
+	case PEACH_DEVICE_ID:
+		pbl_bootstrap_status_reg = PEACH_PBL_BOOTSTRAP_STATUS;
+		pbl_log_sram_start = PEACH_DEBUG_PBL_LOG_SRAM_START;
+		pbl_log_max_size = PEACH_DEBUG_PBL_LOG_SRAM_MAX_SIZE;
+		sbl_log_max_size = PEACH_DEBUG_SBL_LOG_SRAM_MAX_SIZE;
+		break;
+	default:
+		return;
+	}
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pci_reg_read(pci_priv, TCSR_PBL_LOGGING_REG, &pbl_stage);
+	cnss_pci_reg_read(pci_priv, PCIE_BHI_ERRDBG2_REG, &sbl_log_start);
+	cnss_pci_reg_read(pci_priv, PCIE_BHI_ERRDBG3_REG, &sbl_log_size);
+	cnss_pci_reg_read(pci_priv, PBL_WLAN_BOOT_CFG, &pbl_wlan_boot_cfg);
+	cnss_pci_reg_read(pci_priv, pbl_bootstrap_status_reg,
+			  &pbl_bootstrap_status);
+	cnss_pr_dbg("TCSR_PBL_LOGGING: 0x%08x PCIE_BHI_ERRDBG: Start: 0x%08x Size:0x%08x\n",
+		    pbl_stage, sbl_log_start, sbl_log_size);
+	cnss_pr_dbg("PBL_WLAN_BOOT_CFG: 0x%08x PBL_BOOTSTRAP_STATUS: 0x%08x\n",
+		    pbl_wlan_boot_cfg, pbl_bootstrap_status);
+
+	ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
+	if (CNSS_MHI_IN_MISSION_MODE(ee)) {
+		cnss_pr_err("Avoid Dumping PBL log data in Mission mode\n");
+		return;
+	}
+
+	cnss_pr_dbg("Dumping PBL log data\n");
+	for (i = 0; i < pbl_log_max_size; i += sizeof(val)) {
+		mem_addr = pbl_log_sram_start + i;
+		if (cnss_pci_reg_read(pci_priv, mem_addr, &val))
+			break;
+		cnss_pr_dbg("SRAM[0x%x] = 0x%x\n", mem_addr, val);
+	}
+
+	sbl_log_size = (sbl_log_size > sbl_log_max_size ?
+			sbl_log_max_size : sbl_log_size);
+	if (sbl_log_start < sbl_log_def_start ||
+	    sbl_log_start > sbl_log_def_end ||
+	    (sbl_log_start + sbl_log_size) > sbl_log_def_end) {
+		cnss_pr_err("Invalid SBL log data\n");
+		return;
+	}
+
+	ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
+	if (CNSS_MHI_IN_MISSION_MODE(ee)) {
+		cnss_pr_err("Avoid Dumping SBL log data in Mission mode\n");
+		return;
+	}
+
+	cnss_pr_dbg("Dumping SBL log data\n");
+	for (i = 0; i < sbl_log_size; i += sizeof(val)) {
+		mem_addr = sbl_log_start + i;
+		if (cnss_pci_reg_read(pci_priv, mem_addr, &val))
+			break;
+		cnss_pr_dbg("SRAM[0x%x] = 0x%x\n", mem_addr, val);
+	}
+}
+
+#ifdef CONFIG_DISABLE_CNSS_SRAM_DUMP
+static void cnss_pci_dump_sram(struct cnss_pci_data *pci_priv)
+{
+}
+#else
+static void cnss_pci_dump_sram(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+	u32 i, mem_addr;
+	u32 *dump_ptr;
+
+	plat_priv = pci_priv->plat_priv;
+
+	if (plat_priv->device_id != QCA6490_DEVICE_ID ||
+	    cnss_get_host_build_type() != QMI_HOST_BUILD_TYPE_PRIMARY_V01)
+		return;
+
+	if (!plat_priv->sram_dump) {
+		cnss_pr_err("SRAM dump memory is not allocated\n");
+		return;
+	}
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pr_dbg("Dumping SRAM at 0x%lx\n", plat_priv->sram_dump);
+
+	for (i = 0; i < SRAM_DUMP_SIZE; i += sizeof(u32)) {
+		mem_addr = SRAM_START + i;
+		dump_ptr = (u32 *)(plat_priv->sram_dump + i);
+		if (cnss_pci_reg_read(pci_priv, mem_addr, dump_ptr)) {
+			cnss_pr_err("SRAM Dump failed at 0x%x\n", mem_addr);
+			break;
+		}
+		/* Relinquish CPU after dumping 256KB chunks*/
+		if (!(i % CNSS_256KB_SIZE))
+			cond_resched();
+	}
+}
+#endif
+
+static int cnss_pci_handle_mhi_poweron_timeout(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	cnss_fatal_err("MHI power up returns timeout\n");
+
+	if (cnss_mhi_scan_rddm_cookie(pci_priv, DEVICE_RDDM_COOKIE) ||
+	    cnss_get_dev_sol_value(plat_priv) > 0) {
+		/* Wait for RDDM if RDDM cookie is set or device SOL GPIO is
+		 * high. If RDDM times out, PBL/SBL error region may have been
+		 * erased so no need to dump them either.
+		 */
+		if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+		    !pci_priv->pci_link_down_ind) {
+			mod_timer(&pci_priv->dev_rddm_timer,
+				  jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
+		}
+	} else {
+		cnss_pr_dbg("RDDM cookie is not set and device SOL is low\n");
+		cnss_mhi_debug_reg_dump(pci_priv);
+		cnss_pci_bhi_debug_reg_dump(pci_priv);
+		cnss_pci_soc_scratch_reg_dump(pci_priv);
+		/* Dump PBL/SBL error log if RDDM cookie is not set */
+		cnss_pci_dump_bl_sram_mem(pci_priv);
+		cnss_pci_dump_sram(pci_priv);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static char *cnss_mhi_state_to_str(enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		return "INIT";
+	case CNSS_MHI_DEINIT:
+		return "DEINIT";
+	case CNSS_MHI_POWER_ON:
+		return "POWER_ON";
+	case CNSS_MHI_POWERING_OFF:
+		return "POWERING_OFF";
+	case CNSS_MHI_POWER_OFF:
+		return "POWER_OFF";
+	case CNSS_MHI_FORCE_POWER_OFF:
+		return "FORCE_POWER_OFF";
+	case CNSS_MHI_SUSPEND:
+		return "SUSPEND";
+	case CNSS_MHI_RESUME:
+		return "RESUME";
+	case CNSS_MHI_TRIGGER_RDDM:
+		return "TRIGGER_RDDM";
+	case CNSS_MHI_RDDM_DONE:
+		return "RDDM_DONE";
+	default:
+		return "UNKNOWN";
+	}
+};
+
+static int cnss_pci_check_mhi_state_bit(struct cnss_pci_data *pci_priv,
+					enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		if (!test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_DEINIT:
+	case CNSS_MHI_POWER_ON:
+		if (test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state) &&
+		    !test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_FORCE_POWER_OFF:
+		if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_POWER_OFF:
+	case CNSS_MHI_SUSPEND:
+		if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) &&
+		    !test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_RESUME:
+		if (test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_TRIGGER_RDDM:
+		if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) &&
+		    !test_bit(CNSS_MHI_TRIGGER_RDDM, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_RDDM_DONE:
+		return 0;
+	default:
+		cnss_pr_err("Unhandled MHI state: %s(%d)\n",
+			    cnss_mhi_state_to_str(mhi_state), mhi_state);
+	}
+
+	cnss_pr_err("Cannot set MHI state %s(%d) in current MHI state (0x%lx)\n",
+		    cnss_mhi_state_to_str(mhi_state), mhi_state,
+		    pci_priv->mhi_state);
+	if (mhi_state != CNSS_MHI_TRIGGER_RDDM)
+		CNSS_ASSERT(0);
+
+	return -EINVAL;
+}
+
+static int cnss_rddm_trigger_debug(struct cnss_pci_data *pci_priv)
+{
+	int read_val, ret;
+
+	if (!pci_priv || pci_priv->device_id != QCA6490_DEVICE_ID)
+		return -EOPNOTSUPP;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return -EINVAL;
+
+	cnss_pr_err("Write GCC Spare with ACE55 Pattern");
+	cnss_pci_reg_write(pci_priv, GCC_GCC_SPARE_REG_1, 0xACE55);
+	ret = cnss_pci_reg_read(pci_priv, GCC_GCC_SPARE_REG_1, &read_val);
+	cnss_pr_err("Read back GCC Spare: 0x%x, ret: %d", read_val, ret);
+	ret = cnss_pci_reg_read(pci_priv, GCC_PRE_ARES_DEBUG_TIMER_VAL,
+				&read_val);
+	cnss_pr_err("Warm reset allowed check: 0x%x, ret: %d", read_val, ret);
+	return ret;
+}
+
+static int cnss_rddm_trigger_check(struct cnss_pci_data *pci_priv)
+{
+	int read_val, ret;
+	u32 pbl_stage, sbl_log_start, sbl_log_size, pbl_wlan_boot_cfg;
+
+	if (!pci_priv || pci_priv->device_id != QCA6490_DEVICE_ID)
+		return -EOPNOTSUPP;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return -EINVAL;
+
+	ret = cnss_pci_reg_read(pci_priv, GCC_GCC_SPARE_REG_1, &read_val);
+	cnss_pr_err("Read GCC spare to check reset status: 0x%x, ret: %d",
+		    read_val, ret);
+
+	cnss_pci_reg_read(pci_priv, TCSR_PBL_LOGGING_REG, &pbl_stage);
+	cnss_pci_reg_read(pci_priv, PCIE_BHI_ERRDBG2_REG, &sbl_log_start);
+	cnss_pci_reg_read(pci_priv, PCIE_BHI_ERRDBG3_REG, &sbl_log_size);
+	cnss_pci_reg_read(pci_priv, PBL_WLAN_BOOT_CFG, &pbl_wlan_boot_cfg);
+	cnss_pr_dbg("TCSR_PBL_LOGGING: 0x%08x PCIE_BHI_ERRDBG: Start: 0x%08x Size:0x%08x \n",
+		    pbl_stage, sbl_log_start, sbl_log_size);
+	cnss_pr_dbg("PBL_WLAN_BOOT_CFG: 0x%08x\n", pbl_wlan_boot_cfg);
+
+	return ret;
+}
+
+static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv,
+				       enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		set_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_DEINIT:
+		clear_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_POWER_ON:
+		set_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_POWERING_OFF:
+		set_bit(CNSS_MHI_POWERING_OFF, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_POWER_OFF:
+	case CNSS_MHI_FORCE_POWER_OFF:
+		clear_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+		clear_bit(CNSS_MHI_POWERING_OFF, &pci_priv->mhi_state);
+		clear_bit(CNSS_MHI_TRIGGER_RDDM, &pci_priv->mhi_state);
+		clear_bit(CNSS_MHI_RDDM_DONE, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_SUSPEND:
+		set_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_RESUME:
+		clear_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_TRIGGER_RDDM:
+		set_bit(CNSS_MHI_TRIGGER_RDDM, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_RDDM_DONE:
+		set_bit(CNSS_MHI_RDDM_DONE, &pci_priv->mhi_state);
+		break;
+	default:
+		cnss_pr_err("Unhandled MHI state (%d)\n", mhi_state);
+	}
+}
+
+#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)
+{
+	int ret = 0, retry = 0;
+
+	if (pci_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (mhi_state < 0) {
+		cnss_pr_err("Invalid MHI state (%d)\n", mhi_state);
+		return -EINVAL;
+	}
+
+	ret = cnss_pci_check_mhi_state_bit(pci_priv, mhi_state);
+	if (ret)
+		goto out;
+
+	cnss_pr_vdbg("Setting MHI state: %s(%d)\n",
+		     cnss_mhi_state_to_str(mhi_state), mhi_state);
+
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		ret = mhi_prepare_for_power_up(pci_priv->mhi_ctrl);
+		break;
+	case CNSS_MHI_DEINIT:
+		mhi_unprepare_after_power_down(pci_priv->mhi_ctrl);
+		ret = 0;
+		break;
+	case CNSS_MHI_POWER_ON:
+		ret = mhi_sync_power_up(pci_priv->mhi_ctrl);
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
+		/* Only set img_pre_alloc when power up succeeds */
+		if (!ret && !pci_priv->mhi_ctrl->img_pre_alloc) {
+			cnss_pr_dbg("Notify MHI to use already allocated images\n");
+			pci_priv->mhi_ctrl->img_pre_alloc = true;
+		}
+#endif
+		break;
+	case CNSS_MHI_POWER_OFF:
+		mhi_power_down(pci_priv->mhi_ctrl, true);
+		ret = 0;
+		break;
+	case CNSS_MHI_FORCE_POWER_OFF:
+		mhi_power_down(pci_priv->mhi_ctrl, false);
+		ret = 0;
+		break;
+	case CNSS_MHI_SUSPEND:
+retry_mhi_suspend:
+		mutex_lock(&pci_priv->mhi_ctrl->pm_mutex);
+		if (pci_priv->drv_connected_last)
+			ret = cnss_mhi_pm_fast_suspend(pci_priv, true);
+		else
+			ret = mhi_pm_suspend(pci_priv->mhi_ctrl);
+		mutex_unlock(&pci_priv->mhi_ctrl->pm_mutex);
+		if (ret == -EBUSY && retry++ < MHI_SUSPEND_RETRY_MAX_TIMES) {
+			cnss_pr_vdbg("Retry MHI suspend #%d\n", retry);
+			usleep_range(MHI_SUSPEND_RETRY_DELAY_US,
+				     MHI_SUSPEND_RETRY_DELAY_US + 1000);
+			goto retry_mhi_suspend;
+		}
+		break;
+	case CNSS_MHI_RESUME:
+		mutex_lock(&pci_priv->mhi_ctrl->pm_mutex);
+		if (pci_priv->drv_connected_last) {
+			ret = cnss_pci_prevent_l1(&pci_priv->pci_dev->dev);
+			if (ret) {
+				mutex_unlock(&pci_priv->mhi_ctrl->pm_mutex);
+				break;
+			}
+			ret = cnss_mhi_pm_fast_resume(pci_priv, true);
+			cnss_pci_allow_l1(&pci_priv->pci_dev->dev);
+		} else {
+			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;
+	case CNSS_MHI_TRIGGER_RDDM:
+		cnss_rddm_trigger_debug(pci_priv);
+		ret = mhi_force_rddm_mode(pci_priv->mhi_ctrl);
+		if (ret) {
+			cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret);
+			cnss_rddm_trigger_check(pci_priv);
+		}
+		break;
+	case CNSS_MHI_RDDM_DONE:
+		break;
+	default:
+		cnss_pr_err("Unhandled MHI state (%d)\n", mhi_state);
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		goto out;
+
+	cnss_pci_set_mhi_state_bit(pci_priv, mhi_state);
+
+	return 0;
+
+out:
+	cnss_pr_err("Failed to set MHI state: %s(%d), err = %d\n",
+		    cnss_mhi_state_to_str(mhi_state), mhi_state, ret);
+	return ret;
+}
+
+static int cnss_pci_config_msi_addr(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_dev)
+		return -ENODEV;
+
+	if (!pci_dev->msix_enabled)
+		return ret;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(plat_priv->plat_dev->dev.of_node,
+				   "msix-match-addr",
+				   &pci_priv->msix_addr);
+	cnss_pr_dbg("MSI-X Match address is 0x%X\n",
+		    pci_priv->msix_addr);
+
+	return ret;
+}
+
+static int cnss_pci_config_msi_data(struct cnss_pci_data *pci_priv)
+{
+	struct msi_desc *msi_desc;
+	struct cnss_msi_config *msi_config;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	msi_config = pci_priv->msi_config;
+
+	if (pci_dev->msix_enabled) {
+		pci_priv->msi_ep_base_data = msi_config->users[0].base_vector;
+		cnss_pr_dbg("MSI-X base data is %d\n",
+			    pci_priv->msi_ep_base_data);
+		return 0;
+	}
+
+	msi_desc = irq_get_msi_desc(pci_dev->irq);
+	if (!msi_desc) {
+		cnss_pr_err("msi_desc is NULL!\n");
+		return -EINVAL;
+	}
+
+	pci_priv->msi_ep_base_data = msi_desc->msg.data;
+	cnss_pr_dbg("MSI base data is %d\n", pci_priv->msi_ep_base_data);
+
+	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_max_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_vdbg("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");
+		return -ENODEV;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+	if (test_bit(FBC_BYPASS, &plat_priv->ctrl_params.quirks))
+		return 0;
+
+	if (MHI_TIMEOUT_OVERWRITE_MS)
+		pci_priv->mhi_ctrl->timeout_ms = MHI_TIMEOUT_OVERWRITE_MS;
+	cnss_mhi_set_m2_timeout_ms(pci_priv, MHI_M2_TIMEOUT_MS);
+
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_INIT);
+	if (ret)
+		return ret;
+
+	timeout = pci_priv->mhi_ctrl->timeout_ms;
+	/* For non-perf builds the timeout is 10 (default) * 6 seconds */
+	if (cnss_get_host_build_type() == QMI_HOST_BUILD_TYPE_PRIMARY_V01)
+		pci_priv->mhi_ctrl->timeout_ms *= 6;
+	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));
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON);
+	del_timer_sync(&pci_priv->boot_debug_timer);
+	if (ret == 0)
+		cnss_wlan_adsp_pc_enable(pci_priv, false);
+
+	pci_priv->mhi_ctrl->timeout_ms = timeout;
+
+	if (ret == -ETIMEDOUT) {
+		/* This is a special case needs to be handled that if MHI
+		 * power on returns -ETIMEDOUT, controller needs to take care
+		 * the cleanup by calling MHI power down. Force to set the bit
+		 * for driver internal MHI state to make sure it can be handled
+		 * properly later.
+		 */
+		set_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+		ret = cnss_pci_handle_mhi_poweron_timeout(pci_priv);
+	} else if (!ret) {
+		/* kernel may allocate a dummy vector before request_irq and
+		 * then allocate a real vector when request_irq is called.
+		 * So get msi_data here again to avoid spurious interrupt
+		 * as msi_data will configured to srngs.
+		 */
+		if (cnss_pci_is_one_msi(pci_priv))
+			ret = cnss_pci_config_msi_data(pci_priv);
+	}
+
+	return ret;
+}
+
+static void cnss_pci_power_off_mhi(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (test_bit(FBC_BYPASS, &plat_priv->ctrl_params.quirks))
+		return;
+
+	if (!test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state)) {
+		cnss_pr_dbg("MHI is already powered off\n");
+		return;
+	}
+	cnss_wlan_adsp_pc_enable(pci_priv, true);
+	cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME);
+	cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_POWERING_OFF);
+
+	if (!pci_priv->pci_link_down_ind)
+		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF);
+	else
+		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_FORCE_POWER_OFF);
+}
+
+static void cnss_pci_deinit_mhi(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (test_bit(FBC_BYPASS, &plat_priv->ctrl_params.quirks))
+		return;
+
+	if (!test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state)) {
+		cnss_pr_dbg("MHI is already deinited\n");
+		return;
+	}
+
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+}
+
+static void cnss_pci_set_wlaon_pwr_ctrl(struct cnss_pci_data *pci_priv,
+					bool set_vddd4blow, bool set_shutdown,
+					bool do_force_wake)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	int ret;
+	u32 val;
+
+	if (!plat_priv->set_wlaon_pwr_ctrl)
+		return;
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN ||
+	    pci_priv->pci_link_down_ind)
+		return;
+
+	if (do_force_wake)
+		if (cnss_pci_force_wake_get(pci_priv))
+			return;
+
+	ret = cnss_pci_reg_read(pci_priv, WLAON_QFPROM_PWR_CTRL_REG, &val);
+	if (ret) {
+		cnss_pr_err("Failed to read register offset 0x%x, err = %d\n",
+			    WLAON_QFPROM_PWR_CTRL_REG, ret);
+		goto force_wake_put;
+	}
+
+	cnss_pr_dbg("Read register offset 0x%x, val = 0x%x\n",
+		    WLAON_QFPROM_PWR_CTRL_REG, val);
+
+	if (set_vddd4blow)
+		val |= QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;
+	else
+		val &= ~QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK;
+
+	if (set_shutdown)
+		val |= QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;
+	else
+		val &= ~QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK;
+
+	ret = cnss_pci_reg_write(pci_priv, WLAON_QFPROM_PWR_CTRL_REG, val);
+	if (ret) {
+		cnss_pr_err("Failed to write register offset 0x%x, err = %d\n",
+			    WLAON_QFPROM_PWR_CTRL_REG, ret);
+		goto force_wake_put;
+	}
+
+	cnss_pr_dbg("Write val 0x%x to register offset 0x%x\n", val,
+		    WLAON_QFPROM_PWR_CTRL_REG);
+
+	if (set_shutdown)
+		usleep_range(WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US,
+			     WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US);
+
+force_wake_put:
+	if (do_force_wake)
+		cnss_pci_force_wake_put(pci_priv);
+}
+
+static int cnss_pci_get_device_timestamp(struct cnss_pci_data *pci_priv,
+					 u64 *time_us)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	u32 low, high;
+	u64 device_ticks;
+
+	if (!plat_priv->device_freq_hz) {
+		cnss_pr_err("Device time clock frequency is not valid\n");
+		return -EINVAL;
+	}
+
+	switch (pci_priv->device_id) {
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		cnss_pci_reg_read(pci_priv, PCIE_MHI_TIME_LOW, &low);
+		cnss_pci_reg_read(pci_priv, PCIE_MHI_TIME_HIGH, &high);
+		break;
+	default:
+		cnss_pci_reg_read(pci_priv, WLAON_GLOBAL_COUNTER_CTRL3, &low);
+		cnss_pci_reg_read(pci_priv, WLAON_GLOBAL_COUNTER_CTRL4, &high);
+		break;
+	}
+
+	device_ticks = (u64)high << 32 | low;
+	do_div(device_ticks, plat_priv->device_freq_hz / 100000);
+	*time_us = device_ticks * 10;
+
+	return 0;
+}
+
+static void cnss_pci_enable_time_sync_counter(struct cnss_pci_data *pci_priv)
+{
+	switch (pci_priv->device_id) {
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		return;
+	default:
+		break;
+	}
+
+	cnss_pci_reg_write(pci_priv, WLAON_GLOBAL_COUNTER_CTRL5,
+			   TIME_SYNC_ENABLE);
+}
+
+static void cnss_pci_clear_time_sync_counter(struct cnss_pci_data *pci_priv)
+{
+	switch (pci_priv->device_id) {
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		return;
+	default:
+		break;
+	}
+
+	cnss_pci_reg_write(pci_priv, WLAON_GLOBAL_COUNTER_CTRL5,
+			   TIME_SYNC_CLEAR);
+}
+
+
+static void cnss_pci_time_sync_reg_update(struct cnss_pci_data *pci_priv,
+					  u32 low, u32 high)
+{
+	u32 time_reg_low;
+	u32 time_reg_high;
+
+	switch (pci_priv->device_id) {
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		/* Use the next two shadow registers after host's usage */
+		time_reg_low = PCIE_SHADOW_REG_VALUE_0 +
+				(pci_priv->plat_priv->num_shadow_regs_v3 *
+				 SHADOW_REG_LEN_BYTES);
+		time_reg_high = time_reg_low + SHADOW_REG_LEN_BYTES;
+		break;
+	default:
+		time_reg_low = PCIE_SHADOW_REG_VALUE_34;
+		time_reg_high = PCIE_SHADOW_REG_VALUE_35;
+		break;
+	}
+
+	cnss_pci_reg_write(pci_priv, time_reg_low, low);
+	cnss_pci_reg_write(pci_priv, time_reg_high, high);
+
+	cnss_pci_reg_read(pci_priv, time_reg_low, &low);
+	cnss_pci_reg_read(pci_priv, time_reg_high, &high);
+
+	cnss_pr_dbg("Updated time sync regs [0x%x] = 0x%x, [0x%x] = 0x%x\n",
+		    time_reg_low, low, time_reg_high, high);
+}
+
+static int cnss_pci_update_timestamp(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device *dev = &pci_priv->pci_dev->dev;
+	unsigned long flags = 0;
+	u64 host_time_us, device_time_us, offset;
+	u32 low, high;
+	int ret;
+
+	ret = cnss_pci_prevent_l1(dev);
+	if (ret)
+		goto out;
+
+	ret = cnss_pci_force_wake_get(pci_priv);
+	if (ret)
+		goto allow_l1;
+
+	spin_lock_irqsave(&time_sync_lock, flags);
+	cnss_pci_clear_time_sync_counter(pci_priv);
+	cnss_pci_enable_time_sync_counter(pci_priv);
+	host_time_us = cnss_get_host_timestamp(plat_priv);
+	ret = cnss_pci_get_device_timestamp(pci_priv, &device_time_us);
+	cnss_pci_clear_time_sync_counter(pci_priv);
+	spin_unlock_irqrestore(&time_sync_lock, flags);
+	if (ret)
+		goto force_wake_put;
+
+	if (host_time_us < device_time_us) {
+		cnss_pr_err("Host time (%llu us) is smaller than device time (%llu us), stop\n",
+			    host_time_us, device_time_us);
+		ret = -EINVAL;
+		goto force_wake_put;
+	}
+
+	offset = host_time_us - device_time_us;
+	cnss_pr_dbg("Host time = %llu us, device time = %llu us, offset = %llu us\n",
+		    host_time_us, device_time_us, offset);
+
+	low = offset & 0xFFFFFFFF;
+	high = offset >> 32;
+
+	cnss_pci_time_sync_reg_update(pci_priv, low, high);
+
+force_wake_put:
+	cnss_pci_force_wake_put(pci_priv);
+allow_l1:
+	cnss_pci_allow_l1(dev);
+out:
+	return ret;
+}
+
+static void cnss_pci_time_sync_work_hdlr(struct work_struct *work)
+{
+	struct cnss_pci_data *pci_priv =
+		container_of(work, struct cnss_pci_data, time_sync_work.work);
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	unsigned int time_sync_period_ms =
+		plat_priv->ctrl_params.time_sync_period;
+
+	if (test_bit(DISABLE_TIME_SYNC, &plat_priv->ctrl_params.quirks)) {
+		cnss_pr_dbg("Time sync is disabled\n");
+		return;
+	}
+
+	if (!time_sync_period_ms) {
+		cnss_pr_dbg("Skip time sync as time period is 0\n");
+		return;
+	}
+
+	if (cnss_pci_is_device_down(&pci_priv->pci_dev->dev))
+		return;
+
+	if (cnss_pci_pm_runtime_get_sync(pci_priv, RTPM_ID_CNSS) < 0)
+		goto runtime_pm_put;
+
+	mutex_lock(&pci_priv->bus_lock);
+	cnss_pci_update_timestamp(pci_priv);
+	mutex_unlock(&pci_priv->bus_lock);
+	schedule_delayed_work(&pci_priv->time_sync_work,
+			      msecs_to_jiffies(time_sync_period_ms));
+
+runtime_pm_put:
+	cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+	cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+}
+
+static int cnss_pci_start_time_sync_update(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (!plat_priv->device_freq_hz) {
+		cnss_pr_dbg("Device time clock frequency is not valid, skip time sync\n");
+		return -EINVAL;
+	}
+
+	cnss_pci_time_sync_work_hdlr(&pci_priv->time_sync_work.work);
+
+	return 0;
+}
+
+static void cnss_pci_stop_time_sync_update(struct cnss_pci_data *pci_priv)
+{
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return;
+	}
+
+	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)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+
+	cnss_pci_stop_time_sync_update(pci_priv);
+	plat_priv->ctrl_params.time_sync_period = time_sync_period;
+	cnss_pci_start_time_sync_update(pci_priv);
+	cnss_pr_dbg("WLAN time sync period %u ms\n",
+		    plat_priv->ctrl_params.time_sync_period);
+
+	return 0;
+}
+
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_err("Reboot is in progress, skip driver probe\n");
+		return -EINVAL;
+	}
+
+	if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		cnss_pr_dbg("Skip driver probe\n");
+		goto out;
+	}
+
+	if (!pci_priv->driver_ops) {
+		cnss_pr_err("driver_ops is NULL\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+		ret = pci_priv->driver_ops->reinit(pci_priv->pci_dev,
+						   pci_priv->pci_device_id);
+		if (ret) {
+			cnss_pr_err("Failed to reinit host driver, err = %d\n",
+				    ret);
+			goto out;
+		}
+		complete(&plat_priv->recovery_complete);
+	} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+		ret = pci_priv->driver_ops->probe(pci_priv->pci_dev,
+						  pci_priv->pci_device_id);
+		if (ret) {
+			cnss_pr_err("Failed to probe host driver, err = %d\n",
+				    ret);
+			complete_all(&plat_priv->power_up_complete);
+			goto out;
+		}
+		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)) {
+		ret = pci_priv->driver_ops->idle_restart(pci_priv->pci_dev,
+			pci_priv->pci_device_id);
+		if (ret) {
+			cnss_pr_err("Failed to idle restart host driver, err = %d\n",
+				    ret);
+			plat_priv->power_up_error = ret;
+			complete_all(&plat_priv->power_up_complete);
+			goto out;
+		}
+		clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state);
+		complete_all(&plat_priv->power_up_complete);
+	} else {
+		complete(&plat_priv->power_up_complete);
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		__pm_relax(plat_priv->recovery_ws);
+	}
+
+	cnss_pci_start_time_sync_update(pci_priv);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+	int ret;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+
+	if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+	    test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Skip driver remove\n");
+		return 0;
+	}
+
+	if (!pci_priv->driver_ops) {
+		cnss_pr_err("driver_ops is NULL\n");
+		return -EINVAL;
+	}
+
+	cnss_pci_stop_time_sync_update(pci_priv);
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
+		complete(&plat_priv->rddm_complete);
+		pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
+	} else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+		pci_priv->driver_ops->remove(pci_priv->pci_dev);
+		clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+	} else if (test_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
+			    &plat_priv->driver_state)) {
+		ret = pci_priv->driver_ops->idle_shutdown(pci_priv->pci_dev);
+		if (ret == -EAGAIN) {
+			clear_bit(CNSS_DRIVER_IDLE_SHUTDOWN,
+				  &plat_priv->driver_state);
+			return ret;
+		}
+	}
+
+	plat_priv->get_info_cb_ctx = NULL;
+	plat_priv->get_info_cb = NULL;
+	plat_priv->get_driver_async_data_ctx = NULL;
+	plat_priv->get_driver_async_data_cb = NULL;
+
+	return 0;
+}
+
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+				      int modem_current_status)
+{
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	driver_ops = pci_priv->driver_ops;
+	if (!driver_ops || !driver_ops->modem_status)
+		return -EINVAL;
+
+	driver_ops->modem_status(pci_priv->pci_dev, modem_current_status);
+
+	return 0;
+}
+
+int cnss_pci_update_status(struct cnss_pci_data *pci_priv,
+			   enum cnss_driver_status status)
+{
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	driver_ops = pci_priv->driver_ops;
+	if (!driver_ops || !driver_ops->update_status)
+		return -EINVAL;
+
+	cnss_pr_dbg("Update driver status: %d\n", status);
+
+	driver_ops->update_status(pci_priv->pci_dev, status);
+
+	return 0;
+}
+
+static void cnss_pci_misc_reg_dump(struct cnss_pci_data *pci_priv,
+				   struct cnss_misc_reg *misc_reg,
+				   u32 misc_reg_size,
+				   char *reg_name)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	bool do_force_wake_put = true;
+	int i;
+
+	if (!misc_reg)
+		return;
+
+	if (in_interrupt() || irqs_disabled())
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	if (cnss_pci_force_wake_get(pci_priv)) {
+		/* Continue to dump when device has entered RDDM already */
+		if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+			return;
+		do_force_wake_put = false;
+	}
+
+	cnss_pr_dbg("Start to dump %s registers\n", reg_name);
+
+	for (i = 0; i < misc_reg_size; i++) {
+		if (!test_bit(pci_priv->misc_reg_dev_mask,
+			      &misc_reg[i].dev_mask))
+			continue;
+
+		if (misc_reg[i].wr) {
+			if (misc_reg[i].offset ==
+			    QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG &&
+			    i >= 1)
+				misc_reg[i].val =
+				QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG_MSK |
+				misc_reg[i - 1].val;
+			if (cnss_pci_reg_write(pci_priv,
+					       misc_reg[i].offset,
+					       misc_reg[i].val))
+				goto force_wake_put;
+			cnss_pr_vdbg("Write 0x%X to 0x%X\n",
+				     misc_reg[i].val,
+				     misc_reg[i].offset);
+
+		} else {
+			if (cnss_pci_reg_read(pci_priv,
+					      misc_reg[i].offset,
+					      &misc_reg[i].val))
+				goto force_wake_put;
+		}
+	}
+
+force_wake_put:
+	if (do_force_wake_put)
+		cnss_pci_force_wake_put(pci_priv);
+}
+
+static void cnss_pci_dump_misc_reg(struct cnss_pci_data *pci_priv)
+{
+	if (in_interrupt() || irqs_disabled())
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pci_misc_reg_dump(pci_priv, pci_priv->wcss_reg,
+			       WCSS_REG_SIZE, "wcss");
+	cnss_pci_misc_reg_dump(pci_priv, pci_priv->pcie_reg,
+			       PCIE_REG_SIZE, "pcie");
+	cnss_pci_misc_reg_dump(pci_priv, pci_priv->wlaon_reg,
+			       WLAON_REG_SIZE, "wlaon");
+	cnss_pci_misc_reg_dump(pci_priv, pci_priv->syspm_reg,
+			       SYSPM_REG_SIZE, "syspm");
+}
+
+static void cnss_pci_dump_shadow_reg(struct cnss_pci_data *pci_priv)
+{
+	int i, j = 0, array_size = SHADOW_REG_COUNT + SHADOW_REG_INTER_COUNT;
+	u32 reg_offset;
+	bool do_force_wake_put = true;
+
+	if (in_interrupt() || irqs_disabled())
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	if (!pci_priv->debug_reg) {
+		pci_priv->debug_reg = devm_kzalloc(&pci_priv->pci_dev->dev,
+						   sizeof(*pci_priv->debug_reg)
+						   * array_size, GFP_KERNEL);
+		if (!pci_priv->debug_reg)
+			return;
+	}
+
+	if (cnss_pci_force_wake_get(pci_priv))
+		do_force_wake_put = false;
+
+	cnss_pr_dbg("Start to dump shadow registers\n");
+
+	for (i = 0; i < SHADOW_REG_COUNT; i++, j++) {
+		reg_offset = PCIE_SHADOW_REG_VALUE_0 + i * 4;
+		pci_priv->debug_reg[j].offset = reg_offset;
+		if (cnss_pci_reg_read(pci_priv, reg_offset,
+				      &pci_priv->debug_reg[j].val))
+			goto force_wake_put;
+	}
+
+	for (i = 0; i < SHADOW_REG_INTER_COUNT; i++, j++) {
+		reg_offset = PCIE_SHADOW_REG_INTER_0 + i * 4;
+		pci_priv->debug_reg[j].offset = reg_offset;
+		if (cnss_pci_reg_read(pci_priv, reg_offset,
+				      &pci_priv->debug_reg[j].val))
+			goto force_wake_put;
+	}
+
+force_wake_put:
+	if (do_force_wake_put)
+		cnss_pci_force_wake_put(pci_priv);
+}
+
+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, false);
+	if (ret) {
+		cnss_pr_err("Failed to power on device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+		goto power_off;
+	}
+
+	ret = cnss_pci_call_driver_probe(pci_priv);
+	if (ret)
+		goto suspend_link;
+
+	return 0;
+suspend_link:
+	cnss_suspend_pci_link(pci_priv);
+power_off:
+	cnss_power_off_device(plat_priv);
+out:
+	return ret;
+}
+
+static int cnss_qca6174_shutdown(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	cnss_pci_pm_runtime_resume(pci_priv);
+
+	ret = cnss_pci_call_driver_remove(pci_priv);
+	if (ret == -EAGAIN)
+		goto out;
+
+	cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+				   CNSS_BUS_WIDTH_NONE);
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+
+	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);
+
+	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+	clear_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state);
+
+out:
+	return ret;
+}
+
+static void cnss_qca6174_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+	if (pci_priv->driver_ops && pci_priv->driver_ops->crash_shutdown)
+		pci_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
+}
+
+static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_ramdump_info *ramdump_info;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	if (!ramdump_info->ramdump_size)
+		return -EINVAL;
+
+	return cnss_do_ramdump(plat_priv);
+}
+
+static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	unsigned int timeout;
+	int retry = 0, bt_en_gpio = plat_priv->pinctrl_info.bt_en_gpio;
+	int sw_ctrl_gpio = plat_priv->pinctrl_info.sw_ctrl_gpio;
+
+	if (plat_priv->ramdump_info_v2.dump_data_valid) {
+		cnss_pci_clear_dump_info(pci_priv);
+		cnss_pci_power_off_mhi(pci_priv);
+		cnss_suspend_pci_link(pci_priv);
+		cnss_pci_deinit_mhi(pci_priv);
+		cnss_power_off_device(plat_priv);
+	}
+
+	/* Clear QMI send usage count during every power up */
+	pci_priv->qmi_send_usage_count = 0;
+
+	plat_priv->power_up_error = 0;
+retry:
+	ret = cnss_power_on_device(plat_priv, false);
+	if (ret) {
+		cnss_pr_err("Failed to power on device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+		cnss_pr_dbg("Value of SW_CTRL GPIO: %d\n",
+			    cnss_get_input_gpio_value(plat_priv, sw_ctrl_gpio));
+		if (test_bit(IGNORE_PCI_LINK_FAILURE,
+			     &plat_priv->ctrl_params.quirks)) {
+			cnss_pr_dbg("Ignore PCI link resume failure\n");
+			ret = 0;
+			goto out;
+		}
+		if (ret == -EAGAIN && retry++ < POWER_ON_RETRY_MAX_TIMES) {
+			cnss_power_off_device(plat_priv);
+			/* Force toggle BT_EN GPIO low */
+			if (retry == POWER_ON_RETRY_MAX_TIMES) {
+				cnss_pr_dbg("Retry #%d. Set BT_EN GPIO(%u) low\n",
+					    retry, bt_en_gpio);
+				if (bt_en_gpio >= 0)
+					gpio_direction_output(bt_en_gpio, 0);
+				cnss_pr_dbg("BT_EN GPIO val: %d\n",
+					    gpio_get_value(bt_en_gpio));
+			}
+			cnss_pr_dbg("Retry to resume PCI link #%d\n", retry);
+			cnss_pr_dbg("Value of SW_CTRL GPIO: %d\n",
+				    cnss_get_input_gpio_value(plat_priv,
+							      sw_ctrl_gpio));
+			msleep(POWER_ON_RETRY_DELAY_MS * retry);
+			goto retry;
+		}
+		/* Assert when it reaches maximum retries */
+		CNSS_ASSERT(0);
+		goto power_off;
+	}
+
+	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_QMI);
+
+	ret = cnss_pci_start_mhi(pci_priv);
+	if (ret) {
+		cnss_fatal_err("Failed to start MHI, err = %d\n", ret);
+		if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+		    !pci_priv->pci_link_down_ind && timeout) {
+			/* Start recovery directly for MHI start failures */
+			cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+					       CNSS_REASON_DEFAULT);
+		}
+		return 0;
+	}
+
+	if (test_bit(USE_CORE_ONLY_FW, &plat_priv->ctrl_params.quirks)) {
+		clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		return 0;
+	}
+
+	cnss_set_pin_connect_status(plat_priv);
+
+	if (test_bit(QMI_BYPASS, &plat_priv->ctrl_params.quirks)) {
+		ret = cnss_pci_call_driver_probe(pci_priv);
+		if (ret)
+			goto stop_mhi;
+	} else if (timeout) {
+		if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state))
+			timeout += WLAN_COLD_BOOT_CAL_TIMEOUT;
+		else
+			timeout += WLAN_MISSION_MODE_TIMEOUT;
+		mod_timer(&plat_priv->fw_boot_timer,
+			  jiffies + msecs_to_jiffies(timeout));
+	}
+
+	return 0;
+
+stop_mhi:
+	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, true);
+	cnss_pci_power_off_mhi(pci_priv);
+	cnss_suspend_pci_link(pci_priv);
+	cnss_pci_deinit_mhi(pci_priv);
+power_off:
+	cnss_power_off_device(plat_priv);
+out:
+	return ret;
+}
+
+static int cnss_qca6290_shutdown(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	int do_force_wake = true;
+
+	cnss_pci_pm_runtime_resume(pci_priv);
+
+	ret = cnss_pci_call_driver_remove(pci_priv);
+	if (ret == -EAGAIN)
+		goto out;
+
+	cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+				   CNSS_BUS_WIDTH_NONE);
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+
+	if ((test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+	     test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
+	     test_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state) ||
+	     test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state) ||
+	     test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) &&
+	    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);
+
+		if (!plat_priv->recovery_enabled)
+			CNSS_ASSERT(0);
+	}
+
+	if (!cnss_is_device_powered_on(plat_priv)) {
+		cnss_pr_dbg("Device is already powered off, ignore\n");
+		goto skip_power_off;
+	}
+
+	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		do_force_wake = false;
+	cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, do_force_wake);
+
+	/* FBC image will be freed after powering off MHI, so skip
+	 * if RAM dump data is still valid.
+	 */
+	if (plat_priv->ramdump_info_v2.dump_data_valid)
+		goto skip_power_off;
+
+	cnss_pci_power_off_mhi(pci_priv);
+	ret = cnss_suspend_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+	cnss_pci_deinit_mhi(pci_priv);
+	cnss_power_off_device(plat_priv);
+
+skip_power_off:
+	pci_priv->remap_window = 0;
+
+	clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+	clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state)) {
+		clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+		pci_priv->pci_link_down_ind = false;
+	}
+	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+	clear_bit(CNSS_DRIVER_IDLE_SHUTDOWN, &plat_priv->driver_state);
+	memset(&print_optimize, 0, sizeof(print_optimize));
+
+out:
+	return ret;
+}
+
+static void cnss_qca6290_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	set_bit(CNSS_IN_PANIC, &plat_priv->driver_state);
+	cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
+		    plat_priv->driver_state);
+
+	cnss_pci_collect_dump_info(pci_priv, true);
+	clear_bit(CNSS_IN_PANIC, &plat_priv->driver_state);
+}
+
+static int cnss_qca6290_ramdump(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+	struct cnss_dump_data *dump_data = &info_v2->dump_data;
+	struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+	int ret = 0;
+
+	if (!info_v2->dump_data_valid || !dump_seg ||
+	    dump_data->nentries == 0)
+		return 0;
+
+	ret = cnss_do_elf_ramdump(plat_priv);
+
+	cnss_pci_clear_dump_info(pci_priv);
+	cnss_pci_power_off_mhi(pci_priv);
+	cnss_suspend_pci_link(pci_priv);
+	cnss_pci_deinit_mhi(pci_priv);
+	cnss_power_off_device(plat_priv);
+
+	return ret;
+}
+
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	switch (pci_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_powerup(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:
+	case PEACH_DEVICE_ID:
+		ret = cnss_qca6290_powerup(pci_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%x\n",
+			    pci_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	switch (pci_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_shutdown(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:
+	case PEACH_DEVICE_ID:
+		ret = cnss_qca6290_shutdown(pci_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%x\n",
+			    pci_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	switch (pci_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		cnss_qca6174_crash_shutdown(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:
+	case PEACH_DEVICE_ID:
+		cnss_qca6290_crash_shutdown(pci_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%x\n",
+			    pci_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	switch (pci_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_ramdump(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:
+	case PEACH_DEVICE_ID:
+		ret = cnss_qca6290_ramdump(pci_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%x\n",
+			    pci_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+int cnss_pci_is_drv_connected(struct device *dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	return pci_priv->drv_connected_last;
+}
+EXPORT_SYMBOL(cnss_pci_is_drv_connected);
+
+static void cnss_wlan_reg_driver_work(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+	container_of(work, struct cnss_plat_data, wlan_reg_driver_work.work);
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	struct cnss_cal_info *cal_info;
+	unsigned int timeout;
+
+	if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state))
+		return;
+
+	if (test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state)) {
+		goto reg_driver;
+	} else {
+		if (plat_priv->charger_mode) {
+			cnss_pr_err("Ignore calibration timeout in charger mode\n");
+			return;
+		}
+		if (!test_bit(CNSS_IN_COLD_BOOT_CAL,
+			      &plat_priv->driver_state)) {
+			timeout = cnss_get_timeout(plat_priv,
+						   CNSS_TIMEOUT_CALIBRATION);
+			cnss_pr_dbg("File system not ready to start calibration. Wait for %ds..\n",
+				    timeout / 1000);
+			schedule_delayed_work(&plat_priv->wlan_reg_driver_work,
+					      msecs_to_jiffies(timeout));
+			return;
+		}
+
+		del_timer(&plat_priv->fw_boot_timer);
+		if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state) &&
+		    !test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+			cnss_pr_err("Timeout waiting for calibration to complete\n");
+			CNSS_ASSERT(0);
+		}
+		cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL);
+		if (!cal_info)
+			return;
+		cal_info->cal_status = CNSS_CAL_TIMEOUT;
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+				       0, cal_info);
+	}
+reg_driver:
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Reboot/Shutdown is in progress, ignore register driver\n");
+		return;
+	}
+	reinit_completion(&plat_priv->power_up_complete);
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+			       CNSS_EVENT_SYNC_UNKILLABLE,
+			       pci_priv->driver_ops);
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
+{
+	int ret = 0;
+	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;
+
+	if (!cnss_check_driver_loading_allowed()) {
+		cnss_pr_info("No cnss2 dtsi entry present");
+		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;
+	}
+
+	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) {
+				if (plat_priv->device_id == KIWI_DEVICE_ID &&
+				    driver_ops->chip_version != 2) {
+					cnss_pr_err("WLAN HW disabled. kiwi_v2 only supported\n");
+					return -ENODEV;
+				}
+				cnss_pr_info("WLAN register driver deferred for device ID: 0x%x due to HW disable\n",
+					     id_table->device);
+				plat_priv->driver_ops = driver_ops;
+				return 0;
+			}
+			id_table++;
+		}
+		return -ENODEV;
+	}
+
+	if (!test_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state)) {
+		cnss_pr_info("pci probe not yet done for register driver\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) {
+		cnss_pr_err("Driver has already registered\n");
+		return -EEXIST;
+	}
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Reboot/Shutdown is in progress, ignore register driver\n");
+		return -EINVAL;
+	}
+
+	if (!id_table || !pci_dev_present(id_table)) {
+		/* id_table pointer will move from pci_dev_present(),
+		 * so check again using local pointer.
+		 */
+		id_table = driver_ops->id_table;
+		while (id_table && id_table->vendor) {
+			cnss_pr_info("Host driver is built for PCIe device ID 0x%x\n",
+				     id_table->device);
+			id_table++;
+		}
+		cnss_pr_err("Enumerated PCIe device id is 0x%x, reject unsupported driver\n",
+			    pci_priv->device_id);
+		return -ENODEV;
+	}
+
+	if (driver_ops->chip_version != CNSS_CHIP_VER_ANY &&
+	    driver_ops->chip_version != plat_priv->device_version.major_version) {
+		cnss_pr_err("Driver built for chip ver 0x%x, enumerated ver 0x%x, reject unsupported driver\n",
+			    driver_ops->chip_version,
+			    plat_priv->device_version.major_version);
+		return -ENODEV;
+	}
+	set_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state);
+
+	if (plat_priv->device_id == QCN7605_DEVICE_ID &&
+	    driver_ops->get_driver_mode) {
+		plat_priv->driver_mode = driver_ops->get_driver_mode();
+		cnss_pci_update_fw_name(pci_priv);
+	}
+
+	if (!plat_priv->cbc_enabled ||
+	    test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state))
+		goto register_driver;
+
+	pci_priv->driver_ops = driver_ops;
+	/* If Cold Boot Calibration is enabled, it is the 1st step in init
+	 * sequence.CBC is done on file system_ready trigger. Qcacld will be
+	 * loaded from vendor_modprobe.sh at early boot and must be deferred
+	 * until CBC is complete
+	 */
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_CALIBRATION);
+	INIT_DELAYED_WORK(&plat_priv->wlan_reg_driver_work,
+			  cnss_wlan_reg_driver_work);
+	schedule_delayed_work(&plat_priv->wlan_reg_driver_work,
+			      msecs_to_jiffies(timeout));
+	cnss_pr_info("WLAN register driver deferred for Calibration\n");
+	return 0;
+register_driver:
+	reinit_completion(&plat_priv->power_up_complete);
+	ret = cnss_driver_event_post(plat_priv,
+				     CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+				     CNSS_EVENT_SYNC_UNKILLABLE,
+				     driver_ops);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
+{
+	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;
+	}
+
+	mutex_lock(&plat_priv->driver_ops_lock);
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		goto skip_wait_power_up;
+
+	timeout = cnss_get_timeout(plat_priv, CNSS_TIMEOUT_WLAN_WATCHDOG);
+	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+					  msecs_to_jiffies(timeout));
+	if (!ret) {
+		cnss_pr_err("Timeout (%ums) waiting for driver power up to complete\n",
+			    timeout);
+		CNSS_ASSERT(0);
+	}
+
+skip_wait_power_up:
+	if (!test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
+	    !test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		goto skip_wait_recovery;
+
+	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);
+	}
+
+skip_wait_recovery:
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+			       CNSS_EVENT_SYNC_UNKILLABLE, NULL);
+
+	mutex_unlock(&plat_priv->driver_ops_lock);
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv,
+				  void *data)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Reboot or shutdown is in progress, ignore register driver\n");
+		return -EINVAL;
+	}
+
+	set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+	pci_priv->driver_ops = data;
+
+	ret = cnss_pci_dev_powerup(pci_priv);
+	if (ret) {
+		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+		pci_priv->driver_ops = NULL;
+	} else {
+		set_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state);
+	}
+
+	return ret;
+}
+
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -EINVAL;
+
+	plat_priv = pci_priv->plat_priv;
+	set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+	cnss_pci_dev_shutdown(pci_priv);
+	pci_priv->driver_ops = NULL;
+	clear_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state);
+
+	return 0;
+}
+
+static int cnss_pci_suspend_driver(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_wlan_driver *driver_ops = pci_priv->driver_ops;
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+	if (test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state) &&
+	    driver_ops && driver_ops->suspend) {
+		ret = driver_ops->suspend(pci_dev, state);
+		if (ret) {
+			cnss_pr_err("Failed to suspend host driver, err = %d\n",
+				    ret);
+			ret = -EAGAIN;
+		}
+	}
+
+	return ret;
+}
+
+static int cnss_pci_resume_driver(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_wlan_driver *driver_ops = pci_priv->driver_ops;
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state) &&
+	    driver_ops && driver_ops->resume) {
+		ret = driver_ops->resume(pci_dev);
+		if (ret)
+			cnss_pr_err("Failed to resume host driver, err = %d\n",
+				    ret);
+	}
+
+	return ret;
+}
+
+int cnss_pci_suspend_bus(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	int ret = 0;
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN)
+		goto out;
+
+	if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	if (pci_priv->drv_connected_last)
+		goto skip_disable_pci;
+
+	pci_clear_master(pci_dev);
+	cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+	pci_disable_device(pci_dev);
+
+	ret = pci_set_power_state(pci_dev, PCI_D3hot);
+	if (ret)
+		cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
+
+skip_disable_pci:
+	if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
+		ret = -EAGAIN;
+		goto resume_mhi;
+	}
+	pci_priv->pci_link_state = PCI_LINK_DOWN;
+
+	return 0;
+
+resume_mhi:
+	if (!pci_is_enabled(pci_dev))
+		if (pci_enable_device(pci_dev))
+			cnss_pr_err("Failed to enable PCI device\n");
+	if (pci_priv->saved_state)
+		cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+	pci_set_master(pci_dev);
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+out:
+	return ret;
+}
+
+int cnss_pci_resume_bus(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	int ret = 0;
+
+	if (pci_priv->pci_link_state == PCI_LINK_UP)
+		goto out;
+
+	if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
+		cnss_fatal_err("Failed to resume PCI link from suspend\n");
+		cnss_pci_link_down(&pci_dev->dev);
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	pci_priv->pci_link_state = PCI_LINK_UP;
+
+	if (pci_priv->drv_connected_last)
+		goto skip_enable_pci;
+
+	ret = pci_enable_device(pci_dev);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCI device, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (pci_priv->saved_state)
+		cnss_set_pci_config_space(pci_priv,
+					  RESTORE_PCI_CONFIG_SPACE);
+	pci_set_master(pci_dev);
+
+skip_enable_pci:
+	if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME))
+		ret = -EAGAIN;
+out:
+	return ret;
+}
+
+static int cnss_pci_suspend(struct device *dev)
+{
+	int ret = 0;
+	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)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	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 =
+			cnss_pci_get_drv_connected(pci_priv);
+		if (!pci_priv->drv_connected_last) {
+			cnss_pr_dbg("Firmware does not support non-DRV suspend, reject\n");
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+
+	set_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
+
+	ret = cnss_pci_suspend_driver(pci_priv);
+	if (ret)
+		goto clear_flag;
+
+	if (!pci_priv->disable_pc) {
+		mutex_lock(&pci_priv->bus_lock);
+		ret = cnss_pci_suspend_bus(pci_priv);
+		mutex_unlock(&pci_priv->bus_lock);
+		if (ret)
+			goto resume_driver;
+	}
+
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+
+	return 0;
+
+resume_driver:
+	cnss_pci_resume_driver(pci_priv);
+clear_flag:
+	pci_priv->drv_connected_last = 0;
+	clear_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
+out:
+	return ret;
+}
+
+static int cnss_pci_resume(struct device *dev)
+{
+	int ret = 0;
+	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)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	if (pci_priv->pci_link_down_ind)
+		goto out;
+
+	if (!cnss_is_device_powered_on(pci_priv->plat_priv))
+		goto out;
+
+	if (!pci_priv->disable_pc) {
+		mutex_lock(&pci_priv->bus_lock);
+		ret = cnss_pci_resume_bus(pci_priv);
+		mutex_unlock(&pci_priv->bus_lock);
+		if (ret)
+			goto out;
+	}
+
+	ret = cnss_pci_resume_driver(pci_priv);
+
+	pci_priv->drv_connected_last = 0;
+	clear_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
+
+out:
+	return ret;
+}
+
+static int cnss_pci_suspend_noirq(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_wlan_driver *driver_ops;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		goto out;
+
+	if (!cnss_is_device_powered_on(pci_priv->plat_priv))
+		goto out;
+
+	driver_ops = pci_priv->driver_ops;
+	plat_priv = pci_priv->plat_priv;
+	if (test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state) &&
+	    driver_ops && driver_ops->suspend_noirq)
+		ret = driver_ops->suspend_noirq(pci_dev);
+
+	if (pci_priv->disable_pc && !pci_dev->state_saved &&
+	    !pci_priv->plat_priv->use_pm_domain)
+		pci_save_state(pci_dev);
+
+out:
+	return ret;
+}
+
+static int cnss_pci_resume_noirq(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_wlan_driver *driver_ops;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		goto out;
+
+	if (!cnss_is_device_powered_on(pci_priv->plat_priv))
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	driver_ops = pci_priv->driver_ops;
+	if (test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state) &&
+	    driver_ops && driver_ops->resume_noirq &&
+	    !pci_priv->pci_link_down_ind)
+		ret = driver_ops->resume_noirq(pci_dev);
+
+out:
+	return ret;
+}
+
+static int cnss_pci_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	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;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -EAGAIN;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -EAGAIN;
+
+	if (!cnss_is_device_powered_on(pci_priv->plat_priv))
+		return -EAGAIN;
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress!\n");
+		return -EAGAIN;
+	}
+
+	if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks) &&
+	    pci_priv->drv_supported) {
+		pci_priv->drv_connected_last =
+			cnss_pci_get_drv_connected(pci_priv);
+		if (!pci_priv->drv_connected_last) {
+			cnss_pr_dbg("Firmware does not support non-DRV suspend, reject\n");
+			return -EAGAIN;
+		}
+	}
+
+	cnss_pr_vdbg("Runtime suspend start\n");
+
+	driver_ops = pci_priv->driver_ops;
+	if (driver_ops && driver_ops->runtime_ops &&
+	    driver_ops->runtime_ops->runtime_suspend)
+		ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
+	else
+		ret = cnss_auto_suspend(dev);
+
+	if (ret)
+		pci_priv->drv_connected_last = 0;
+
+	cnss_pr_vdbg("Runtime suspend status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_pci_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -EAGAIN;
+
+	if (!cnss_is_device_powered_on(pci_priv->plat_priv))
+		return -EAGAIN;
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress!\n");
+		return -EAGAIN;
+	}
+
+	cnss_pr_vdbg("Runtime resume start\n");
+
+	driver_ops = pci_priv->driver_ops;
+	if (driver_ops && driver_ops->runtime_ops &&
+	    driver_ops->runtime_ops->runtime_resume)
+		ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
+	else
+		ret = cnss_auto_resume(dev);
+
+	cnss_pr_vdbg("Runtime resume status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_pci_runtime_idle(struct device *dev)
+{
+	cnss_pr_vdbg("Runtime idle\n");
+
+	pm_request_autosuspend(dev);
+
+	return -EBUSY;
+}
+
+int cnss_wlan_pm_control(struct device *dev, bool vote)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	ret = cnss_pci_disable_pc(pci_priv, vote);
+	if (ret)
+		return ret;
+
+	pci_priv->disable_pc = vote;
+	cnss_pr_dbg("%s PCIe power collapse\n", vote ? "disable" : "enable");
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+
+static void cnss_pci_pm_runtime_get_record(struct cnss_pci_data *pci_priv,
+					   enum cnss_rtpm_id id)
+{
+	if (id >= RTPM_ID_MAX)
+		return;
+
+	atomic_inc(&pci_priv->pm_stats.runtime_get);
+	atomic_inc(&pci_priv->pm_stats.runtime_get_id[id]);
+	pci_priv->pm_stats.runtime_get_timestamp_id[id] =
+		cnss_get_host_timestamp(pci_priv->plat_priv);
+}
+
+static void cnss_pci_pm_runtime_put_record(struct cnss_pci_data *pci_priv,
+					   enum cnss_rtpm_id id)
+{
+	if (id >= RTPM_ID_MAX)
+		return;
+
+	atomic_inc(&pci_priv->pm_stats.runtime_put);
+	atomic_inc(&pci_priv->pm_stats.runtime_put_id[id]);
+	pci_priv->pm_stats.runtime_put_timestamp_id[id] =
+		cnss_get_host_timestamp(pci_priv->plat_priv);
+}
+
+void cnss_pci_pm_runtime_show_usage_count(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev;
+
+	if (!pci_priv)
+		return;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	cnss_pr_dbg("Runtime PM usage count: %d\n",
+		    atomic_read(&dev->power.usage_count));
+}
+
+int cnss_pci_pm_request_resume(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev;
+	enum rpm_status status;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	status = dev->power.runtime_status;
+	if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+		cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+			     (void *)_RET_IP_);
+
+	return pm_request_resume(dev);
+}
+
+int cnss_pci_pm_runtime_resume(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev;
+	enum rpm_status status;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	status = dev->power.runtime_status;
+	if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+		cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+			     (void *)_RET_IP_);
+
+	return pm_runtime_resume(dev);
+}
+
+int cnss_pci_pm_runtime_get(struct cnss_pci_data *pci_priv,
+			    enum cnss_rtpm_id id)
+{
+	struct device *dev;
+	enum rpm_status status;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	status = dev->power.runtime_status;
+	if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+		cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+			     (void *)_RET_IP_);
+
+	cnss_pci_pm_runtime_get_record(pci_priv, id);
+
+	return pm_runtime_get(dev);
+}
+
+int cnss_pci_pm_runtime_get_sync(struct cnss_pci_data *pci_priv,
+				 enum cnss_rtpm_id id)
+{
+	struct device *dev;
+	enum rpm_status status;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	status = dev->power.runtime_status;
+	if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+		cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+			     (void *)_RET_IP_);
+
+	cnss_pci_pm_runtime_get_record(pci_priv, id);
+
+	return pm_runtime_get_sync(dev);
+}
+
+void cnss_pci_pm_runtime_get_noresume(struct cnss_pci_data *pci_priv,
+				      enum cnss_rtpm_id id)
+{
+	if (!pci_priv)
+		return;
+
+	cnss_pci_pm_runtime_get_record(pci_priv, id);
+	pm_runtime_get_noresume(&pci_priv->pci_dev->dev);
+}
+
+int cnss_pci_pm_runtime_put_autosuspend(struct cnss_pci_data *pci_priv,
+					enum cnss_rtpm_id id)
+{
+	struct device *dev;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	if (atomic_read(&dev->power.usage_count) == 0) {
+		cnss_pr_dbg("Ignore excessive runtime PM put operation\n");
+		return -EINVAL;
+	}
+
+	cnss_pci_pm_runtime_put_record(pci_priv, id);
+
+	return pm_runtime_put_autosuspend(&pci_priv->pci_dev->dev);
+}
+
+void cnss_pci_pm_runtime_put_noidle(struct cnss_pci_data *pci_priv,
+				    enum cnss_rtpm_id id)
+{
+	struct device *dev;
+
+	if (!pci_priv)
+		return;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	if (atomic_read(&dev->power.usage_count) == 0) {
+		cnss_pr_dbg("Ignore excessive runtime PM put operation\n");
+		return;
+	}
+
+	cnss_pci_pm_runtime_put_record(pci_priv, id);
+	pm_runtime_put_noidle(&pci_priv->pci_dev->dev);
+}
+
+void cnss_pci_pm_runtime_mark_last_busy(struct cnss_pci_data *pci_priv)
+{
+	if (!pci_priv)
+		return;
+
+	pm_runtime_mark_last_busy(&pci_priv->pci_dev->dev);
+}
+
+int cnss_auto_suspend(struct device *dev)
+{
+	int ret = 0;
+	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)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	mutex_lock(&pci_priv->bus_lock);
+	if (!pci_priv->qmi_send_usage_count) {
+		ret = cnss_pci_suspend_bus(pci_priv);
+		if (ret) {
+			mutex_unlock(&pci_priv->bus_lock);
+			return ret;
+		}
+	}
+
+	cnss_pci_set_auto_suspended(pci_priv, 1);
+	mutex_unlock(&pci_priv->bus_lock);
+
+	cnss_pci_set_monitor_wake_intr(pci_priv, true);
+
+	/* For suspend temporarily set bandwidth vote to NONE and dont save in
+	 * current_bw_vote as in resume path we should vote for last used
+	 * bandwidth vote. Also ignore error if bw voting is not setup.
+	 */
+	cnss_setup_bus_bandwidth(plat_priv, CNSS_BUS_WIDTH_NONE, false);
+	return 0;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(struct device *dev)
+{
+	int ret = 0;
+	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)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	mutex_lock(&pci_priv->bus_lock);
+	ret = cnss_pci_resume_bus(pci_priv);
+	if (ret) {
+		mutex_unlock(&pci_priv->bus_lock);
+		return ret;
+	}
+
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+	mutex_unlock(&pci_priv->bus_lock);
+
+	cnss_request_bus_bandwidth(dev, plat_priv->icc.current_bw_vote);
+	pci_priv->drv_connected_last = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pci_force_wake_request_sync(struct device *dev, int timeout_us)
+{
+	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;
+	struct mhi_controller *mhi_ctrl;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return 0;
+	}
+
+	mhi_ctrl = pci_priv->mhi_ctrl;
+	if (!mhi_ctrl)
+		return -EINVAL;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		return -EAGAIN;
+
+	if (timeout_us) {
+		/* Busy wait for timeout_us */
+		return cnss_mhi_device_get_sync_atomic(pci_priv,
+						       timeout_us, false);
+	} else {
+		/* Sleep wait for mhi_ctrl->timeout_ms */
+		return mhi_device_get_sync(mhi_ctrl->mhi_dev);
+	}
+}
+EXPORT_SYMBOL(cnss_pci_force_wake_request_sync);
+
+int cnss_pci_force_wake_request(struct device *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;
+	struct mhi_controller *mhi_ctrl;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return 0;
+	}
+
+	mhi_ctrl = pci_priv->mhi_ctrl;
+	if (!mhi_ctrl)
+		return -EINVAL;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		return -EAGAIN;
+
+	mhi_device_get(mhi_ctrl->mhi_dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_pci_force_wake_request);
+
+int cnss_pci_is_device_awake(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct mhi_controller *mhi_ctrl;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return 0;
+	}
+
+	mhi_ctrl = pci_priv->mhi_ctrl;
+	if (!mhi_ctrl)
+		return -EINVAL;
+
+	return (mhi_ctrl->dev_state == MHI_STATE_M0);
+}
+EXPORT_SYMBOL(cnss_pci_is_device_awake);
+
+int cnss_pci_force_wake_release(struct device *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;
+	struct mhi_controller *mhi_ctrl;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return 0;
+	}
+
+	mhi_ctrl = pci_priv->mhi_ctrl;
+	if (!mhi_ctrl)
+		return -EINVAL;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
+		return -EAGAIN;
+
+	mhi_device_put(mhi_ctrl->mhi_dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_pci_force_wake_release);
+
+int cnss_pci_qmi_send_get(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	mutex_lock(&pci_priv->bus_lock);
+	if (cnss_pci_get_auto_suspended(pci_priv) &&
+	    !pci_priv->qmi_send_usage_count)
+		ret = cnss_pci_resume_bus(pci_priv);
+	pci_priv->qmi_send_usage_count++;
+	cnss_pr_buf("Increased QMI send usage count to %d\n",
+		    pci_priv->qmi_send_usage_count);
+	mutex_unlock(&pci_priv->bus_lock);
+
+	return ret;
+}
+
+int cnss_pci_qmi_send_put(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	mutex_lock(&pci_priv->bus_lock);
+	if (pci_priv->qmi_send_usage_count)
+		pci_priv->qmi_send_usage_count--;
+	cnss_pr_buf("Decreased QMI send usage count to %d\n",
+		    pci_priv->qmi_send_usage_count);
+	if (cnss_pci_get_auto_suspended(pci_priv) &&
+	    !pci_priv->qmi_send_usage_count &&
+	    !cnss_pcie_is_device_down(pci_priv))
+		ret = cnss_pci_suspend_bus(pci_priv);
+	mutex_unlock(&pci_priv->bus_lock);
+
+	return ret;
+}
+
+int cnss_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb,
+			       uint32_t len, uint8_t slotid)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_fw_mem *fw_mem;
+	void *mem = NULL;
+	int i, ret;
+	u32 *status;
+
+	if (!plat_priv)
+		return -EINVAL;
+
+	fw_mem = plat_priv->fw_mem;
+	if (slotid >= AFC_MAX_SLOT) {
+		cnss_pr_err("Invalid slot id %d\n", slotid);
+		ret = -EINVAL;
+		goto err;
+	}
+	if (len > AFC_SLOT_SIZE) {
+		cnss_pr_err("len %d greater than slot size", len);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == QMI_WLFW_AFC_MEM_V01) {
+			mem = fw_mem[i].va;
+			status = mem + (slotid * AFC_SLOT_SIZE);
+			break;
+		}
+	}
+
+	if (!mem) {
+		cnss_pr_err("AFC mem is not available\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memcpy(mem + (slotid * AFC_SLOT_SIZE), afcdb, len);
+	if (len < AFC_SLOT_SIZE)
+		memset(mem + (slotid * AFC_SLOT_SIZE) + len,
+		       0, AFC_SLOT_SIZE - len);
+	status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_SUCCESS);
+
+	return 0;
+err:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_send_buffer_to_afcmem);
+
+int cnss_reset_afcmem(struct device *dev, uint8_t slotid)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_fw_mem *fw_mem;
+	void *mem = NULL;
+	int i, ret;
+
+	if (!plat_priv)
+		return -EINVAL;
+
+	fw_mem = plat_priv->fw_mem;
+	if (slotid >= AFC_MAX_SLOT) {
+		cnss_pr_err("Invalid slot id %d\n", slotid);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == QMI_WLFW_AFC_MEM_V01) {
+			mem = fw_mem[i].va;
+			break;
+		}
+	}
+
+	if (!mem) {
+		cnss_pr_err("AFC mem is not available\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE);
+	return 0;
+
+err:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_reset_afcmem);
+
+int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	struct device *dev = &pci_priv->pci_dev->dev;
+	int i;
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (!fw_mem[i].va && fw_mem[i].size) {
+retry:
+			fw_mem[i].va =
+				dma_alloc_attrs(dev, fw_mem[i].size,
+						&fw_mem[i].pa, GFP_KERNEL,
+						fw_mem[i].attrs);
+
+			if (!fw_mem[i].va) {
+				if ((fw_mem[i].attrs &
+				    DMA_ATTR_FORCE_CONTIGUOUS)) {
+					fw_mem[i].attrs &=
+						~DMA_ATTR_FORCE_CONTIGUOUS;
+
+					cnss_pr_dbg("Fallback to non-contiguous memory for FW, Mem type: %u\n",
+						    fw_mem[i].type);
+					goto retry;
+				}
+				cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
+					    fw_mem[i].size, fw_mem[i].type);
+				CNSS_ASSERT(0);
+				return -ENOMEM;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	struct device *dev = &pci_priv->pci_dev->dev;
+	int i;
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].va && fw_mem[i].size) {
+			cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+				    fw_mem[i].va, &fw_mem[i].pa,
+				    fw_mem[i].size, fw_mem[i].type);
+			dma_free_attrs(dev, fw_mem[i].size,
+				       fw_mem[i].va, fw_mem[i].pa,
+				       fw_mem[i].attrs);
+			fw_mem[i].va = NULL;
+			fw_mem[i].pa = 0;
+			fw_mem[i].size = 0;
+			fw_mem[i].type = 0;
+		}
+	}
+
+	plat_priv->fw_mem_seg_len = 0;
+}
+
+int cnss_pci_alloc_qdss_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem;
+	int i, j;
+
+	for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) {
+		if (!qdss_mem[i].va && qdss_mem[i].size) {
+			qdss_mem[i].va =
+				dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						   qdss_mem[i].size,
+						   &qdss_mem[i].pa,
+						   GFP_KERNEL);
+			if (!qdss_mem[i].va) {
+				cnss_pr_err("Failed to allocate QDSS memory for FW, size: 0x%zx, type: %u, chuck-ID: %d\n",
+					    qdss_mem[i].size,
+					    qdss_mem[i].type, i);
+				break;
+			}
+		}
+	}
+
+	/* Best-effort allocation for QDSS trace */
+	if (i < plat_priv->qdss_mem_seg_len) {
+		for (j = i; j < plat_priv->qdss_mem_seg_len; j++) {
+			qdss_mem[j].type = 0;
+			qdss_mem[j].size = 0;
+		}
+		plat_priv->qdss_mem_seg_len = i;
+	}
+
+	return 0;
+}
+
+void cnss_pci_free_qdss_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem;
+	int i;
+
+	for (i = 0; i < plat_priv->qdss_mem_seg_len; i++) {
+		if (qdss_mem[i].va && qdss_mem[i].size) {
+			cnss_pr_dbg("Freeing memory for QDSS: pa: %pa, size: 0x%zx, type: %u\n",
+				    &qdss_mem[i].pa, qdss_mem[i].size,
+				    qdss_mem[i].type);
+			dma_free_coherent(&pci_priv->pci_dev->dev,
+					  qdss_mem[i].size, qdss_mem[i].va,
+					  qdss_mem[i].pa);
+			qdss_mem[i].va = NULL;
+			qdss_mem[i].pa = 0;
+			qdss_mem[i].size = 0;
+			qdss_mem[i].type = 0;
+		}
+	}
+	plat_priv->qdss_mem_seg_len = 0;
+}
+
+int cnss_pci_load_tme_patch(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_lite_mem = &plat_priv->tme_lite_mem;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	char *tme_patch_filename = NULL;
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	switch (pci_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		if (plat_priv->device_version.major_version == FW_V1_NUMBER)
+			tme_patch_filename = TME_PATCH_FILE_NAME_1_0;
+		else if (plat_priv->device_version.major_version == FW_V2_NUMBER)
+			tme_patch_filename = TME_PATCH_FILE_NAME_2_0;
+		break;
+	case QCA6174_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	default:
+		cnss_pr_dbg("TME-L not supported for device ID: (0x%x)\n",
+			    pci_priv->device_id);
+		return 0;
+	}
+
+	if (!tme_lite_mem->va && !tme_lite_mem->size) {
+		scnprintf(filename, MAX_FIRMWARE_NAME_LEN, "%s", tme_patch_filename);
+
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load TME-L patch: %s, ret: %d\n",
+				    filename, ret);
+			return ret;
+		}
+
+		tme_lite_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &tme_lite_mem->pa,
+						GFP_KERNEL);
+		if (!tme_lite_mem->va) {
+			cnss_pr_err("Failed to allocate memory for M3, size: 0x%zx\n",
+				    fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(tme_lite_mem->va, fw_entry->data, fw_entry->size);
+		tme_lite_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_tme_lite_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_lite_mem = &plat_priv->tme_lite_mem;
+
+	if (tme_lite_mem->va && tme_lite_mem->size) {
+		cnss_pr_dbg("Freeing memory for TME patch, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+			    tme_lite_mem->va, &tme_lite_mem->pa, tme_lite_mem->size);
+		dma_free_coherent(&pci_priv->pci_dev->dev, tme_lite_mem->size,
+				  tme_lite_mem->va, tme_lite_mem->pa);
+	}
+
+	tme_lite_mem->va = NULL;
+	tme_lite_mem->pa = 0;
+	tme_lite_mem->size = 0;
+}
+
+int cnss_pci_load_tme_opt_file(struct cnss_pci_data *pci_priv,
+				enum wlfw_tme_lite_file_type_v01 file)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_lite_mem = NULL;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	char *tme_opt_filename = NULL;
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	switch (pci_priv->device_id) {
+	case PEACH_DEVICE_ID:
+		if (file == WLFW_TME_LITE_OEM_FUSE_FILE_V01) {
+			tme_opt_filename = TME_OEM_FUSE_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[0];
+		} else if (file == WLFW_TME_LITE_RPR_FILE_V01) {
+			tme_opt_filename = TME_RPR_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[1];
+		} else if (file == WLFW_TME_LITE_DPR_FILE_V01) {
+			tme_opt_filename = TME_DPR_FILE_NAME;
+			tme_lite_mem = &plat_priv->tme_opt_file_mem[2];
+		}
+		break;
+	case QCA6174_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	default:
+		cnss_pr_dbg("TME-L opt file: %s not supported for device ID: (0x%x)\n",
+			    tme_opt_filename, pci_priv->device_id);
+		return 0;
+	}
+
+	if (!tme_lite_mem)
+		return 0;
+
+	if (!tme_lite_mem->va && !tme_lite_mem->size) {
+		cnss_pci_add_fw_prefix_name(pci_priv, filename,
+					    tme_opt_filename);
+
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load TME-L opt file: %s, ret: %d\n",
+				    filename, ret);
+			return ret;
+		}
+
+		tme_lite_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &tme_lite_mem->pa,
+						GFP_KERNEL);
+		if (!tme_lite_mem->va) {
+			cnss_pr_err("Failed to allocate memory for TME-L opt file %s,size: 0x%zx\n",
+				    filename, fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(tme_lite_mem->va, fw_entry->data, fw_entry->size);
+		tme_lite_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_tme_opt_file_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *tme_opt_file_mem = plat_priv->tme_opt_file_mem;
+	int i = 0;
+
+	for (i = 0; i < QMI_WLFW_MAX_TME_OPT_FILE_NUM; i++) {
+		if (tme_opt_file_mem[i].va && tme_opt_file_mem[i].size) {
+			cnss_pr_dbg("Free memory for TME opt file,va:0x%pK, pa:%pa, size:0x%zx\n",
+				tme_opt_file_mem[i].va, &tme_opt_file_mem[i].pa,
+				tme_opt_file_mem[i].size);
+			dma_free_coherent(&pci_priv->pci_dev->dev, tme_opt_file_mem[i].size,
+				tme_opt_file_mem[i].va, tme_opt_file_mem[i].pa);
+		}
+		tme_opt_file_mem[i].va = NULL;
+		tme_opt_file_mem[i].pa = 0;
+		tme_opt_file_mem[i].size = 0;
+	}
+}
+
+int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	char *phy_filename = DEFAULT_PHY_UCODE_FILE_NAME;
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	/* Use forward compatibility here since for any recent device
+	 * it should use DEFAULT_PHY_UCODE_FILE_NAME.
+	 */
+	switch (pci_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		cnss_pr_err("Invalid device ID (0x%x) to load phy image\n",
+			    pci_priv->device_id);
+		return -EINVAL;
+	case QCA6290_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+		phy_filename = DEFAULT_PHY_M3_FILE_NAME;
+		break;
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		switch (plat_priv->device_version.major_version) {
+		case FW_V2_NUMBER:
+			phy_filename = PHY_UCODE_V2_FILE_NAME;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (!m3_mem->va && !m3_mem->size) {
+		cnss_pci_add_fw_prefix_name(pci_priv, filename,
+					    phy_filename);
+
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load M3 image: %s\n", filename);
+			return ret;
+		}
+
+		m3_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &m3_mem->pa,
+						GFP_KERNEL);
+		if (!m3_mem->va) {
+			cnss_pr_err("Failed to allocate memory for M3, size: 0x%zx\n",
+				    fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(m3_mem->va, fw_entry->data, fw_entry->size);
+		m3_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+
+	if (m3_mem->va && m3_mem->size) {
+		cnss_pr_dbg("Freeing memory for M3, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+			    m3_mem->va, &m3_mem->pa, m3_mem->size);
+		dma_free_coherent(&pci_priv->pci_dev->dev, m3_mem->size,
+				  m3_mem->va, m3_mem->pa);
+	}
+
+	m3_mem->va = NULL;
+	m3_mem->pa = 0;
+	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
+
+int cnss_pci_load_aux(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *aux_mem = &plat_priv->aux_mem;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	char *aux_filename = DEFAULT_AUX_FILE_NAME;
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	if (!aux_mem->va && !aux_mem->size) {
+		cnss_pci_add_fw_prefix_name(pci_priv, filename,
+					    aux_filename);
+
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load AUX image: %s\n", filename);
+			return ret;
+		}
+
+		aux_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &aux_mem->pa,
+						GFP_KERNEL);
+		if (!aux_mem->va) {
+			cnss_pr_err("Failed to allocate memory for AUX, size: 0x%zx\n",
+				    fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(aux_mem->va, fw_entry->data, fw_entry->size);
+		aux_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_aux_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *aux_mem = &plat_priv->aux_mem;
+
+	if (aux_mem->va && aux_mem->size) {
+		cnss_pr_dbg("Freeing memory for AUX, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+			    aux_mem->va, &aux_mem->pa, aux_mem->size);
+		dma_free_coherent(&pci_priv->pci_dev->dev, aux_mem->size,
+				  aux_mem->va, aux_mem->pa);
+	}
+
+	aux_mem->va = NULL;
+	aux_mem->pa = 0;
+	aux_mem->size = 0;
+}
+
+void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return;
+
+	cnss_fatal_err("Timeout waiting for FW ready indication\n");
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return;
+
+	if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Ignore FW ready timeout for calibration mode\n");
+		return;
+	}
+
+	cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+			       CNSS_REASON_TIMEOUT);
+}
+
+static void cnss_pci_deinit_smmu(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->iommu_domain = NULL;
+}
+
+int cnss_pci_get_iova(struct cnss_pci_data *pci_priv, u64 *addr, u64 *size)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	if (!pci_priv->smmu_iova_len)
+		return -EINVAL;
+
+	*addr = pci_priv->smmu_iova_start;
+	*size = pci_priv->smmu_iova_len;
+
+	return 0;
+}
+
+int cnss_pci_get_iova_ipa(struct cnss_pci_data *pci_priv, u64 *addr, u64 *size)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	if (!pci_priv->smmu_iova_ipa_len)
+		return -EINVAL;
+
+	*addr = pci_priv->smmu_iova_ipa_start;
+	*size = pci_priv->smmu_iova_ipa_len;
+
+	return 0;
+}
+
+bool cnss_pci_is_smmu_s1_enabled(struct cnss_pci_data *pci_priv)
+{
+	if (pci_priv)
+		return pci_priv->smmu_s1_enable;
+
+	return false;
+}
+struct iommu_domain *cnss_smmu_get_domain(struct device *dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+	if (!pci_priv)
+		return NULL;
+
+	return pci_priv->iommu_domain;
+}
+EXPORT_SYMBOL(cnss_smmu_get_domain);
+
+int cnss_smmu_map(struct device *dev,
+		  phys_addr_t paddr, uint32_t *iova_addr, size_t size)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+	struct cnss_plat_data *plat_priv;
+	unsigned long iova;
+	size_t len;
+	int ret = 0;
+	int flag = IOMMU_READ | IOMMU_WRITE;
+	struct pci_dev *root_port;
+	struct device_node *root_of_node;
+	bool dma_coherent = false;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	if (!iova_addr) {
+		cnss_pr_err("iova_addr is NULL, paddr %pa, size %zu\n",
+			    &paddr, size);
+		return -EINVAL;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+
+	len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE);
+	iova = roundup(pci_priv->smmu_iova_ipa_current, PAGE_SIZE);
+
+	if (pci_priv->iommu_geometry &&
+	    iova >= pci_priv->smmu_iova_ipa_start +
+		    pci_priv->smmu_iova_ipa_len) {
+		cnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
+			    iova,
+			    &pci_priv->smmu_iova_ipa_start,
+			    pci_priv->smmu_iova_ipa_len);
+		return -ENOMEM;
+	}
+
+	if (!test_bit(DISABLE_IO_COHERENCY,
+		      &plat_priv->ctrl_params.quirks)) {
+		root_port = pcie_find_root_port(pci_priv->pci_dev);
+		if (!root_port) {
+			cnss_pr_err("Root port is null, so dma_coherent is disabled\n");
+		} else {
+			root_of_node = root_port->dev.of_node;
+			if (root_of_node && root_of_node->parent) {
+				dma_coherent =
+				    of_property_read_bool(root_of_node->parent,
+							  "dma-coherent");
+			cnss_pr_dbg("dma-coherent is %s\n",
+				    dma_coherent ? "enabled" : "disabled");
+			if (dma_coherent)
+				flag |= IOMMU_CACHE;
+			}
+		}
+	}
+
+	cnss_pr_dbg("IOMMU map: iova %lx, len %zu\n", iova, len);
+
+	ret = cnss_iommu_map(pci_priv->iommu_domain, iova,
+			     rounddown(paddr, PAGE_SIZE), len, flag);
+	if (ret) {
+		cnss_pr_err("PA to IOVA mapping failed, ret %d\n", ret);
+		return ret;
+	}
+
+	pci_priv->smmu_iova_ipa_current = iova + len;
+	*iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));
+	cnss_pr_dbg("IOMMU map: iova_addr %lx\n", *iova_addr);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_smmu_map);
+
+int cnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+	unsigned long iova;
+	size_t unmapped;
+	size_t len;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	iova = rounddown(iova_addr, PAGE_SIZE);
+	len = roundup(size + iova_addr - iova, PAGE_SIZE);
+
+	if (iova >= pci_priv->smmu_iova_ipa_start +
+		    pci_priv->smmu_iova_ipa_len) {
+		cnss_pr_err("Out of IOVA space to unmap, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
+			    iova,
+			    &pci_priv->smmu_iova_ipa_start,
+			    pci_priv->smmu_iova_ipa_len);
+		return -ENOMEM;
+	}
+
+	cnss_pr_dbg("IOMMU unmap: iova %lx, len %zu\n", iova, len);
+
+	unmapped = iommu_unmap(pci_priv->iommu_domain, iova, len);
+	if (unmapped != len) {
+		cnss_pr_err("IOMMU unmap failed, unmapped = %zu, requested = %zu\n",
+			    unmapped, len);
+		return -EINVAL;
+	}
+
+	pci_priv->smmu_iova_ipa_current = iova;
+	return 0;
+}
+EXPORT_SYMBOL(cnss_smmu_unmap);
+
+int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	info->va = pci_priv->bar;
+	info->pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM);
+	info->chip_id = plat_priv->chip_info.chip_id;
+	info->chip_family = plat_priv->chip_info.chip_family;
+	info->board_id = plat_priv->board_info.board_id;
+	info->soc_id = plat_priv->soc_info.soc_id;
+	info->fw_version = plat_priv->fw_version_info.fw_version;
+	strlcpy(info->fw_build_timestamp,
+		plat_priv->fw_version_info.fw_build_timestamp,
+		sizeof(info->fw_build_timestamp));
+	memcpy(&info->device_version, &plat_priv->device_version,
+	       sizeof(info->device_version));
+	memcpy(&info->dev_mem_info, &plat_priv->dev_mem_info,
+	       sizeof(info->dev_mem_info));
+	memcpy(&info->fw_build_id, &plat_priv->fw_build_id,
+	       sizeof(info->fw_build_id));
+
+	return 0;
+}
+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_irq_set_affinity_hint(struct cnss_pci_data *pci_priv,
+					  unsigned int vec,
+					  const struct cpumask *cpumask)
+{
+	int ret;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	ret = irq_set_affinity_hint(pci_irq_vector(pci_dev, vec),
+				    cpumask);
+
+	return ret;
+}
+
+static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	int num_vectors;
+	struct cnss_msi_config *msi_config;
+
+	if (pci_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (cnss_pci_is_force_one_msi(pci_priv)) {
+		ret = cnss_pci_get_one_msi_assignment(pci_priv);
+		cnss_pr_dbg("force one msi\n");
+	} else {
+		ret = cnss_pci_get_msi_assignment(pci_priv);
+	}
+	if (ret) {
+		cnss_pr_err("Failed to get MSI assignment, err = %d\n", ret);
+		goto out;
+	}
+
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("msi_config is NULL!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	num_vectors = pci_alloc_irq_vectors(pci_dev,
+					    msi_config->total_vectors,
+					    msi_config->total_vectors,
+					    PCI_IRQ_MSI | PCI_IRQ_MSIX);
+	if ((num_vectors != msi_config->total_vectors) &&
+	    !cnss_pci_fallback_one_msi(pci_priv, &num_vectors)) {
+		cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d",
+			    msi_config->total_vectors, num_vectors);
+		if (num_vectors >= 0)
+			ret = -EINVAL;
+		goto reset_msi_config;
+	}
+
+	/* With VT-d disabled on x86 platform, only one pci irq vector is
+	 * allocated. Once suspend the irq may be migrated to CPU0 if it was
+	 * affine to other CPU with one new msi vector re-allocated.
+	 * The observation cause the issue about no irq handler for vector
+	 * once resume.
+	 * The fix is to set irq vector affinity to CPU0 before calling
+	 * request_irq to avoid the irq migration.
+	 */
+	if (cnss_pci_is_one_msi(pci_priv)) {
+		ret = cnss_pci_irq_set_affinity_hint(pci_priv,
+						     0,
+						     cpumask_of(0));
+		if (ret) {
+			cnss_pr_err("Failed to affinize irq vector to CPU0\n");
+			goto free_msi_vector;
+		}
+	}
+
+	if (cnss_pci_config_msi_addr(pci_priv)) {
+		ret = -EINVAL;
+		goto free_msi_vector;
+	}
+
+	if (cnss_pci_config_msi_data(pci_priv)) {
+		ret = -EINVAL;
+		goto free_msi_vector;
+	}
+
+	return 0;
+
+free_msi_vector:
+	if (cnss_pci_is_one_msi(pci_priv))
+		cnss_pci_irq_set_affinity_hint(pci_priv, 0, NULL);
+	pci_free_irq_vectors(pci_priv->pci_dev);
+reset_msi_config:
+	pci_priv->msi_config = NULL;
+out:
+	return ret;
+}
+
+static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv)
+{
+	if (pci_priv->device_id == QCA6174_DEVICE_ID)
+		return;
+
+	if (cnss_pci_is_one_msi(pci_priv))
+		cnss_pci_irq_set_affinity_hint(pci_priv, 0, NULL);
+
+	pci_free_irq_vectors(pci_priv->pci_dev);
+}
+
+int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
+				 int *num_vectors, u32 *user_base_data,
+				 u32 *base_vector)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+	struct cnss_msi_config *msi_config;
+	int idx;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("MSI is not supported.\n");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < msi_config->total_users; idx++) {
+		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+			*num_vectors = msi_config->users[idx].num_vectors;
+			*user_base_data = msi_config->users[idx].base_vector
+				+ pci_priv->msi_ep_base_data;
+			*base_vector = msi_config->users[idx].base_vector;
+			/*Add only single print for each user*/
+			if (print_optimize.msi_log_chk[idx]++)
+				goto skip_print;
+
+			cnss_pr_dbg("Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+				    user_name, *num_vectors, *user_base_data,
+				    *base_vector);
+skip_print:
+			return 0;
+		}
+	}
+
+	cnss_pr_err("Failed to find MSI assignment for %s!\n", user_name);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_get_user_msi_assignment);
+
+int cnss_get_msi_irq(struct device *dev, unsigned int vector)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	int irq_num;
+
+	irq_num = pci_irq_vector(pci_dev, vector);
+	cnss_pr_dbg("Get IRQ number %d for vector index %d\n", irq_num, vector);
+
+	return irq_num;
+}
+EXPORT_SYMBOL(cnss_get_msi_irq);
+
+bool cnss_is_one_msi(struct device *dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+	if (!pci_priv)
+		return false;
+
+	return cnss_pci_is_one_msi(pci_priv);
+}
+EXPORT_SYMBOL(cnss_is_one_msi);
+
+void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
+			  u32 *msi_addr_high)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv;
+	u16 control;
+
+	if (!pci_dev)
+		return;
+
+	pci_priv = cnss_get_pci_priv(pci_dev);
+	if (!pci_priv)
+		return;
+
+	if (pci_dev->msix_enabled) {
+		*msi_addr_low = pci_priv->msix_addr;
+		*msi_addr_high = 0;
+		if (!print_optimize.msi_addr_chk++)
+			cnss_pr_dbg("Get MSI low addr = 0x%x, high addr = 0x%x\n",
+				    *msi_addr_low, *msi_addr_high);
+		return;
+	}
+
+	pci_read_config_word(pci_dev, pci_dev->msi_cap + PCI_MSI_FLAGS,
+			     &control);
+	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
+			      msi_addr_low);
+	/* Return MSI high address only when device supports 64-bit MSI */
+	if (control & PCI_MSI_FLAGS_64BIT)
+		pci_read_config_dword(pci_dev,
+				      pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
+				      msi_addr_high);
+	else
+		*msi_addr_high = 0;
+	 /*Add only single print as the address is constant*/
+	 if (!print_optimize.msi_addr_chk++)
+		cnss_pr_dbg("Get MSI low addr = 0x%x, high addr = 0x%x\n",
+			    *msi_addr_low, *msi_addr_high);
+}
+EXPORT_SYMBOL(cnss_get_msi_address);
+
+u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv)
+{
+	int ret, num_vectors;
+	u32 user_base_data, base_vector;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+					   WAKE_MSI_NAME, &num_vectors,
+					   &user_base_data, &base_vector);
+	if (ret) {
+		cnss_pr_err("WAKE MSI is not valid\n");
+		return 0;
+	}
+
+	return user_base_data;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0))
+static inline int cnss_pci_set_dma_mask(struct pci_dev *pci_dev, u64 mask)
+{
+	return dma_set_mask(&pci_dev->dev, mask);
+}
+
+static inline int cnss_pci_set_coherent_dma_mask(struct pci_dev *pci_dev,
+	u64 mask)
+{
+	return dma_set_coherent_mask(&pci_dev->dev, mask);
+}
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) */
+static inline int cnss_pci_set_dma_mask(struct pci_dev *pci_dev, u64 mask)
+{
+	return pci_set_dma_mask(pci_dev, mask);
+}
+
+static inline int cnss_pci_set_coherent_dma_mask(struct pci_dev *pci_dev,
+	u64 mask)
+{
+	return pci_set_consistent_dma_mask(pci_dev, mask);
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) */
+
+static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	u16 device_id;
+
+	pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id);
+	if (device_id != pci_priv->pci_device_id->device)  {
+		cnss_pr_err("PCI device ID mismatch, config ID: 0x%x, probe ID: 0x%x\n",
+			    device_id, pci_priv->pci_device_id->device);
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = pci_assign_resource(pci_dev, PCI_BAR_NUM);
+	if (ret) {
+		pr_err("Failed to assign PCI resource, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = pci_enable_device(pci_dev);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = pci_request_region(pci_dev, PCI_BAR_NUM, "cnss");
+	if (ret) {
+		cnss_pr_err("Failed to request PCI region, err = %d\n", ret);
+		goto disable_device;
+	}
+
+	switch (device_id) {
+	case QCA6174_DEVICE_ID:
+	case QCN7605_DEVICE_ID:
+		pci_priv->dma_bit_mask = PCI_DMA_MASK_32_BIT;
+		break;
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		pci_priv->dma_bit_mask = PCI_DMA_MASK_36_BIT;
+		break;
+	default:
+		pci_priv->dma_bit_mask = PCI_DMA_MASK_32_BIT;
+		break;
+	}
+
+	cnss_pr_dbg("Set PCI DMA MASK (0x%llx)\n", pci_priv->dma_bit_mask);
+
+	ret = cnss_pci_set_dma_mask(pci_dev, pci_priv->dma_bit_mask);
+	if (ret) {
+		cnss_pr_err("Failed to set PCI DMA mask, err = %d\n", ret);
+		goto release_region;
+	}
+
+	ret = cnss_pci_set_coherent_dma_mask(pci_dev, pci_priv->dma_bit_mask);
+	if (ret) {
+		cnss_pr_err("Failed to set PCI coherent DMA mask, err = %d\n",
+			    ret);
+		goto release_region;
+	}
+
+	pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0);
+	if (!pci_priv->bar) {
+		cnss_pr_err("Failed to do PCI IO map!\n");
+		ret = -EIO;
+		goto release_region;
+	}
+
+	/* Save default config space without BME enabled */
+	pci_save_state(pci_dev);
+	pci_priv->default_state = pci_store_saved_state(pci_dev);
+
+	pci_set_master(pci_dev);
+
+	return 0;
+
+release_region:
+	pci_release_region(pci_dev, PCI_BAR_NUM);
+disable_device:
+	pci_disable_device(pci_dev);
+out:
+	return ret;
+}
+
+static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	pci_clear_master(pci_dev);
+	pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state);
+	pci_load_and_free_saved_state(pci_dev, &pci_priv->default_state);
+
+	if (pci_priv->bar) {
+		pci_iounmap(pci_dev, pci_priv->bar);
+		pci_priv->bar = NULL;
+	}
+
+	pci_release_region(pci_dev, PCI_BAR_NUM);
+	if (pci_is_enabled(pci_dev))
+		pci_disable_device(pci_dev);
+}
+
+static void cnss_pci_dump_qdss_reg(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	int i, array_size = ARRAY_SIZE(qdss_csr) - 1;
+	gfp_t gfp = GFP_KERNEL;
+	u32 reg_offset;
+
+	if (in_interrupt() || irqs_disabled())
+		gfp = GFP_ATOMIC;
+
+	if (!plat_priv->qdss_reg) {
+		plat_priv->qdss_reg = devm_kzalloc(&pci_priv->pci_dev->dev,
+						   sizeof(*plat_priv->qdss_reg)
+						   * array_size, gfp);
+		if (!plat_priv->qdss_reg)
+			return;
+	}
+
+	cnss_pr_dbg("Start to dump qdss registers\n");
+
+	for (i = 0; qdss_csr[i].name; i++) {
+		reg_offset = QDSS_APB_DEC_CSR_BASE + qdss_csr[i].offset;
+		if (cnss_pci_reg_read(pci_priv, reg_offset,
+				      &plat_priv->qdss_reg[i]))
+			return;
+		cnss_pr_dbg("%s[0x%x] = 0x%x\n", qdss_csr[i].name, reg_offset,
+			    plat_priv->qdss_reg[i]);
+	}
+}
+
+static void cnss_pci_dump_ce_reg(struct cnss_pci_data *pci_priv,
+				 enum cnss_ce_index ce)
+{
+	int i;
+	u32 ce_base = ce * CE_REG_INTERVAL;
+	u32 reg_offset, src_ring_base, dst_ring_base, cmn_base, val;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+		src_ring_base = QCA6390_CE_SRC_RING_REG_BASE;
+		dst_ring_base = QCA6390_CE_DST_RING_REG_BASE;
+		cmn_base = QCA6390_CE_COMMON_REG_BASE;
+		break;
+	case QCA6490_DEVICE_ID:
+		src_ring_base = QCA6490_CE_SRC_RING_REG_BASE;
+		dst_ring_base = QCA6490_CE_DST_RING_REG_BASE;
+		cmn_base = QCA6490_CE_COMMON_REG_BASE;
+		break;
+	default:
+		return;
+	}
+
+	switch (ce) {
+	case CNSS_CE_09:
+	case CNSS_CE_10:
+		for (i = 0; ce_src[i].name; i++) {
+			reg_offset = src_ring_base + ce_base + ce_src[i].offset;
+			if (cnss_pci_reg_read(pci_priv, reg_offset, &val))
+				return;
+			cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n",
+				    ce, ce_src[i].name, reg_offset, val);
+		}
+
+		for (i = 0; ce_dst[i].name; i++) {
+			reg_offset = dst_ring_base + ce_base + ce_dst[i].offset;
+			if (cnss_pci_reg_read(pci_priv, reg_offset, &val))
+				return;
+			cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n",
+				    ce, ce_dst[i].name, reg_offset, val);
+		}
+		break;
+	case CNSS_CE_COMMON:
+		for (i = 0; ce_cmn[i].name; i++) {
+			reg_offset = cmn_base  + ce_cmn[i].offset;
+			if (cnss_pci_reg_read(pci_priv, reg_offset, &val))
+				return;
+			cnss_pr_dbg("CE_COMMON_%s[0x%x] = 0x%x\n",
+				    ce_cmn[i].name, reg_offset, val);
+		}
+		break;
+	default:
+		cnss_pr_err("Unsupported CE[%d] registers dump\n", ce);
+	}
+}
+
+static void cnss_pci_dump_debug_reg(struct cnss_pci_data *pci_priv)
+{
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	cnss_pr_dbg("Start to dump debug registers\n");
+
+	cnss_mhi_debug_reg_dump(pci_priv);
+	cnss_pci_bhi_debug_reg_dump(pci_priv);
+	cnss_pci_soc_scratch_reg_dump(pci_priv);
+	cnss_pci_dump_ce_reg(pci_priv, CNSS_CE_COMMON);
+	cnss_pci_dump_ce_reg(pci_priv, CNSS_CE_09);
+	cnss_pci_dump_ce_reg(pci_priv, CNSS_CE_10);
+}
+
+static int cnss_pci_assert_host_sol(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+
+	ret = cnss_get_host_sol_value(pci_priv->plat_priv);
+	if (ret) {
+		if (ret < 0) {
+			cnss_pr_dbg("Host SOL functionality is not enabled\n");
+			return ret;
+		} else {
+			cnss_pr_dbg("Host SOL is already high\n");
+			/*
+			 * Return success if HOST SOL is already high.
+			 * This will indicate caller that a HOST SOL is
+			 * already asserted from some other thread and
+			 * no further action required from the caller.
+			 */
+			return 0;
+		}
+	}
+
+	cnss_pr_dbg("Assert host SOL GPIO to retry RDDM, expecting link down\n");
+	cnss_set_host_sol_value(pci_priv->plat_priv, 1);
+
+	return 0;
+}
+
+static void cnss_pci_mhi_reg_dump(struct cnss_pci_data *pci_priv)
+{
+	if (!cnss_pci_check_link_status(pci_priv))
+		cnss_mhi_debug_reg_dump(pci_priv);
+
+	cnss_pci_bhi_debug_reg_dump(pci_priv);
+	cnss_pci_soc_scratch_reg_dump(pci_priv);
+	cnss_pci_dump_misc_reg(pci_priv);
+	cnss_pci_dump_shadow_reg(pci_priv);
+}
+
+int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+	int retry = 0;
+	enum mhi_ee_type mhi_ee;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Always wait here to avoid missing WAKE assert for RDDM
+	 * before link recovery
+	 */
+	ret = wait_for_completion_timeout(&pci_priv->wake_event_complete,
+					  msecs_to_jiffies(WAKE_EVENT_TIMEOUT));
+	if (!ret)
+		cnss_pr_err("Timeout waiting for wake event after link down\n");
+
+	ret = cnss_suspend_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+		del_timer(&pci_priv->dev_rddm_timer);
+		return ret;
+	}
+
+retry:
+	/*
+	 * After PCIe link resumes, 20 to 400 ms delay is observerved
+	 * before device moves to RDDM.
+	 */
+	msleep(RDDM_LINK_RECOVERY_RETRY_DELAY_MS);
+	mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
+	if (mhi_ee == MHI_EE_RDDM) {
+		del_timer(&pci_priv->dev_rddm_timer);
+		cnss_pr_info("Device in RDDM after link recovery, try to collect dump\n");
+		cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+				       CNSS_REASON_RDDM);
+		return 0;
+	} else if (retry++ < RDDM_LINK_RECOVERY_RETRY) {
+		cnss_pr_dbg("Wait for RDDM after link recovery, retry #%d, Device EE: %d\n",
+			    retry, mhi_ee);
+		goto retry;
+	}
+
+	if (!cnss_pci_assert_host_sol(pci_priv))
+		return 0;
+	cnss_mhi_debug_reg_dump(pci_priv);
+	cnss_pci_bhi_debug_reg_dump(pci_priv);
+	cnss_pci_soc_scratch_reg_dump(pci_priv);
+	cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+			       CNSS_REASON_TIMEOUT);
+	return 0;
+}
+
+int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) ||
+	    test_bit(CNSS_MHI_POWERING_OFF, &pci_priv->mhi_state))
+		return -EINVAL;
+	/*
+	 * Call pm_runtime_get_sync insteat of auto_resume to get
+	 * reference and make sure runtime_suspend wont get called.
+	 */
+	ret = cnss_pci_pm_runtime_get_sync(pci_priv, RTPM_ID_CNSS);
+	if (ret < 0)
+		goto runtime_pm_put;
+	/*
+	 * In some scenarios, cnss_pci_pm_runtime_get_sync
+	 * might not resume PCI bus. For those cases do auto resume.
+	 */
+	cnss_auto_resume(&pci_priv->pci_dev->dev);
+
+	if (!pci_priv->is_smmu_fault)
+		cnss_pci_mhi_reg_dump(pci_priv);
+
+	/* If link is still down here, directly trigger link down recovery */
+	ret = cnss_pci_check_link_status(pci_priv);
+	if (ret) {
+		cnss_pci_link_down(&pci_priv->pci_dev->dev);
+		cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+		cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+		return 0;
+	}
+
+	/*
+	 * Fist try MHI SYS_ERR, if fails try HOST SOL and return.
+	 * If SOL is not enabled try HOST Reset Rquest after MHI
+	 * SYS_ERRR fails.
+	 */
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM);
+	if (ret) {
+		if (pci_priv->is_smmu_fault) {
+			cnss_pci_mhi_reg_dump(pci_priv);
+			pci_priv->is_smmu_fault = false;
+		}
+		if (!test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) ||
+		    test_bit(CNSS_MHI_POWERING_OFF, &pci_priv->mhi_state)) {
+			cnss_pr_dbg("MHI is not powered on, ignore RDDM failure\n");
+			cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+			cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+			return 0;
+		}
+		cnss_fatal_err("Failed to trigger RDDM, err = %d\n", ret);
+		if (!cnss_pci_assert_host_sol(pci_priv)) {
+			cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+			cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+			return 0;
+		}
+
+		cnss_pr_dbg("Sending Host Reset Req\n");
+		if (!cnss_mhi_force_reset(pci_priv)) {
+			ret = 0;
+			goto mhi_reg_dump;
+		}
+
+		cnss_pci_dump_debug_reg(pci_priv);
+		cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+				       CNSS_REASON_DEFAULT);
+		ret = 0;
+		goto runtime_pm_put;
+	}
+
+mhi_reg_dump:
+	if (pci_priv->is_smmu_fault) {
+		cnss_pci_mhi_reg_dump(pci_priv);
+		pci_priv->is_smmu_fault = false;
+	}
+
+	if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
+		mod_timer(&pci_priv->dev_rddm_timer,
+			  jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
+	}
+
+runtime_pm_put:
+	cnss_pci_pm_runtime_mark_last_busy(pci_priv);
+	cnss_pci_pm_runtime_put_autosuspend(pci_priv, RTPM_ID_CNSS);
+	return ret;
+}
+
+static void cnss_pci_add_dump_seg(struct cnss_pci_data *pci_priv,
+				  struct cnss_dump_seg *dump_seg,
+				  enum cnss_fw_dump_type type, int seg_no,
+				  void *va, dma_addr_t dma, size_t size)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device *dev = &pci_priv->pci_dev->dev;
+	phys_addr_t pa;
+
+	dump_seg->address = dma;
+	dump_seg->v_address = va;
+	dump_seg->size = size;
+	dump_seg->type = type;
+
+	cnss_pr_dbg("Seg: %x, va: %pK, dma: %pa, size: 0x%zx\n",
+		    seg_no, va, &dma, size);
+
+	if (type == CNSS_FW_CAL || cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS))
+		return;
+
+	cnss_minidump_add_region(plat_priv, type, seg_no, va, pa, size);
+}
+
+static void cnss_pci_remove_dump_seg(struct cnss_pci_data *pci_priv,
+				     struct cnss_dump_seg *dump_seg,
+				     enum cnss_fw_dump_type type, int seg_no,
+				     void *va, dma_addr_t dma, size_t size)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device *dev = &pci_priv->pci_dev->dev;
+	phys_addr_t pa;
+
+	cnss_va_to_pa(dev, size, va, dma, &pa, DMA_ATTR_FORCE_CONTIGUOUS);
+	cnss_minidump_remove_region(plat_priv, type, seg_no, va, pa, size);
+}
+
+int cnss_pci_call_driver_uevent(struct cnss_pci_data *pci_priv,
+				enum cnss_driver_status status, void *data)
+{
+	struct cnss_uevent_data uevent_data;
+	struct cnss_wlan_driver *driver_ops;
+
+	driver_ops = pci_priv->driver_ops;
+	if (!driver_ops || !driver_ops->update_event) {
+		cnss_pr_dbg("Hang event driver ops is NULL\n");
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Calling driver uevent: %d\n", status);
+
+	uevent_data.status = status;
+	uevent_data.data = data;
+
+	return driver_ops->update_event(pci_priv->pci_dev, &uevent_data);
+}
+
+static void cnss_pci_send_hang_event(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	struct cnss_hang_event hang_event;
+	void *hang_data_va = NULL;
+	u64 offset = 0;
+	u16 length = 0;
+	int i = 0;
+
+	if (!fw_mem || !plat_priv->fw_mem_seg_len)
+		return;
+
+	memset(&hang_event, 0, sizeof(hang_event));
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+		offset = HST_HANG_DATA_OFFSET;
+		length = HANG_DATA_LENGTH;
+		break;
+	case QCA6490_DEVICE_ID:
+		/* Fallback to hard-coded values if hang event params not
+		 * present in QMI. Once all the firmware branches have the
+		 * fix to send params over QMI, this can be removed.
+		 */
+		if (plat_priv->hang_event_data_len) {
+			offset = plat_priv->hang_data_addr_offset;
+			length = plat_priv->hang_event_data_len;
+		} else {
+			offset = HSP_HANG_DATA_OFFSET;
+			length = HANG_DATA_LENGTH;
+		}
+		break;
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		offset = plat_priv->hang_data_addr_offset;
+		length = plat_priv->hang_event_data_len;
+		break;
+	case QCN7605_DEVICE_ID:
+		offset = GNO_HANG_DATA_OFFSET;
+		length = HANG_DATA_LENGTH;
+		break;
+	default:
+		cnss_pr_err("Skip Hang Event Data as unsupported Device ID received: %d\n",
+			    pci_priv->device_id);
+		return;
+	}
+
+	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == QMI_WLFW_MEM_TYPE_DDR_V01 &&
+		    fw_mem[i].va) {
+			/* The offset must be < (fw_mem size- hangdata length) */
+			if (!(offset <= fw_mem[i].size - length))
+				goto exit;
+
+			hang_data_va = fw_mem[i].va + offset;
+			hang_event.hang_event_data = kmemdup(hang_data_va,
+							     length,
+							     GFP_ATOMIC);
+			if (!hang_event.hang_event_data) {
+				cnss_pr_dbg("Hang data memory alloc failed\n");
+				return;
+			}
+			hang_event.hang_event_data_len = length;
+			break;
+		}
+	}
+
+	cnss_pci_call_driver_uevent(pci_priv, CNSS_HANG_EVENT, &hang_event);
+
+	kfree(hang_event.hang_event_data);
+	hang_event.hang_event_data = NULL;
+	return;
+exit:
+	cnss_pr_dbg("Invalid hang event params, offset:0x%x, length:0x%x\n",
+		    plat_priv->hang_data_addr_offset,
+		    plat_priv->hang_event_data_len);
+}
+
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_ssr_driver_dump_entry *ssr_entry;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	size_t num_entries_loaded = 0;
+	int x;
+	int ret = -1;
+
+	ssr_entry = kmalloc(sizeof(*ssr_entry) * CNSS_HOST_DUMP_TYPE_MAX, GFP_KERNEL);
+	if (!ssr_entry) {
+		cnss_pr_err("ssr_entry malloc failed");
+		return;
+	}
+
+	if (pci_priv->driver_ops &&
+	    pci_priv->driver_ops->collect_driver_dump) {
+		ret = pci_priv->driver_ops->collect_driver_dump(pci_priv->pci_dev,
+								ssr_entry,
+								&num_entries_loaded);
+	}
+
+	if (!ret) {
+		for (x = 0; x < num_entries_loaded; x++) {
+			cnss_pr_info("Idx:%d, ptr: %p, name: %s, size: %d\n",
+				     x, ssr_entry[x].buffer_pointer,
+				     ssr_entry[x].region_name,
+				     ssr_entry[x].buffer_size);
+		}
+
+		cnss_do_host_ramdump(plat_priv, ssr_entry, num_entries_loaded);
+	} else {
+		cnss_pr_info("Host SSR elf dump collection feature disabled\n");
+	}
+
+	kfree(ssr_entry);
+}
+#endif
+
+void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_dump_data *dump_data =
+		&plat_priv->ramdump_info_v2.dump_data;
+	struct cnss_dump_seg *dump_seg =
+		plat_priv->ramdump_info_v2.dump_data_vaddr;
+	struct image_info *fw_image, *rddm_image;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int ret, i, j;
+
+	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+	    !test_bit(CNSS_IN_PANIC, &plat_priv->driver_state))
+		cnss_pci_send_hang_event(pci_priv);
+
+	if (test_bit(CNSS_MHI_RDDM_DONE, &pci_priv->mhi_state)) {
+		cnss_pr_dbg("RAM dump is already collected, skip\n");
+		return;
+	}
+
+	if (!cnss_is_device_powered_on(plat_priv)) {
+		cnss_pr_dbg("Device is already powered off, skip\n");
+		return;
+	}
+
+	if (!in_panic) {
+		mutex_lock(&pci_priv->bus_lock);
+		ret = cnss_pci_check_link_status(pci_priv);
+		if (ret) {
+			if (ret != -EACCES) {
+				mutex_unlock(&pci_priv->bus_lock);
+				return;
+			}
+			if (cnss_pci_resume_bus(pci_priv)) {
+				mutex_unlock(&pci_priv->bus_lock);
+				return;
+			}
+		}
+		mutex_unlock(&pci_priv->bus_lock);
+	} else {
+		if (cnss_pci_check_link_status(pci_priv))
+			return;
+		/* Inside panic handler, reduce timeout for RDDM to avoid
+		 * unnecessary hypervisor watchdog bite.
+		 */
+		pci_priv->mhi_ctrl->timeout_ms /= 2;
+	}
+
+	cnss_mhi_debug_reg_dump(pci_priv);
+	cnss_pci_bhi_debug_reg_dump(pci_priv);
+	cnss_pci_soc_scratch_reg_dump(pci_priv);
+	cnss_pci_dump_misc_reg(pci_priv);
+	cnss_rddm_trigger_debug(pci_priv);
+	ret = mhi_download_rddm_image(pci_priv->mhi_ctrl, in_panic);
+	if (ret) {
+		cnss_fatal_err("Failed to download RDDM image, err = %d\n",
+			       ret);
+		if (!cnss_pci_assert_host_sol(pci_priv))
+			return;
+		cnss_rddm_trigger_check(pci_priv);
+		cnss_pci_dump_debug_reg(pci_priv);
+		return;
+	}
+	cnss_rddm_trigger_check(pci_priv);
+	fw_image = pci_priv->mhi_ctrl->fbc_image;
+	rddm_image = pci_priv->mhi_ctrl->rddm_image;
+	dump_data->nentries = 0;
+
+	if (plat_priv->qdss_mem_seg_len)
+		cnss_pci_dump_qdss_reg(pci_priv);
+	cnss_mhi_dump_sfr(pci_priv);
+
+	if (!dump_seg) {
+		cnss_pr_warn("FW image dump collection not setup");
+		goto skip_dump;
+	}
+
+	cnss_pr_dbg("Collect FW image dump segment, nentries %d\n",
+		    fw_image->entries);
+
+	for (i = 0; i < fw_image->entries; i++) {
+		cnss_pci_add_dump_seg(pci_priv, dump_seg, CNSS_FW_IMAGE, i,
+				      fw_image->mhi_buf[i].buf,
+				      fw_image->mhi_buf[i].dma_addr,
+				      fw_image->mhi_buf[i].len);
+		dump_seg++;
+	}
+
+	dump_data->nentries += fw_image->entries;
+
+	cnss_pr_dbg("Collect RDDM image dump segment, nentries %d\n",
+		    rddm_image->entries);
+
+	for (i = 0; i < rddm_image->entries; i++) {
+		cnss_pci_add_dump_seg(pci_priv, dump_seg, CNSS_FW_RDDM, i,
+				      rddm_image->mhi_buf[i].buf,
+				      rddm_image->mhi_buf[i].dma_addr,
+				      rddm_image->mhi_buf[i].len);
+		dump_seg++;
+	}
+
+	dump_data->nentries += rddm_image->entries;
+
+	for (i = 0, j = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == CNSS_MEM_TYPE_DDR) {
+			if (fw_mem[i].attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
+				cnss_pr_dbg("Collect remote heap dump segment\n");
+				cnss_pci_add_dump_seg(pci_priv, dump_seg,
+						      CNSS_FW_REMOTE_HEAP, j,
+						      fw_mem[i].va,
+						      fw_mem[i].pa,
+						      fw_mem[i].size);
+				dump_seg++;
+				dump_data->nentries++;
+				j++;
+			} else {
+				cnss_pr_dbg("Skip remote heap dumps as it is non-contiguous\n");
+			}
+		} else if (fw_mem[i].type == CNSS_MEM_CAL_V01) {
+				cnss_pr_dbg("Collect CAL memory dump segment\n");
+				cnss_pci_add_dump_seg(pci_priv, dump_seg,
+						      CNSS_FW_CAL, j,
+						      fw_mem[i].va,
+						      fw_mem[i].pa,
+						      fw_mem[i].size);
+				dump_seg++;
+				dump_data->nentries++;
+				j++;
+		}
+	}
+
+	if (dump_data->nentries > 0)
+		plat_priv->ramdump_info_v2.dump_data_valid = true;
+
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_DONE);
+
+skip_dump:
+	complete(&plat_priv->rddm_complete);
+}
+
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_dump_seg *dump_seg =
+		plat_priv->ramdump_info_v2.dump_data_vaddr;
+	struct image_info *fw_image, *rddm_image;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int i, j;
+
+	if (!dump_seg)
+		return;
+
+	fw_image = pci_priv->mhi_ctrl->fbc_image;
+	rddm_image = pci_priv->mhi_ctrl->rddm_image;
+
+	for (i = 0; i < fw_image->entries; i++) {
+		cnss_pci_remove_dump_seg(pci_priv, dump_seg, CNSS_FW_IMAGE, i,
+					 fw_image->mhi_buf[i].buf,
+					 fw_image->mhi_buf[i].dma_addr,
+					 fw_image->mhi_buf[i].len);
+		dump_seg++;
+	}
+
+	for (i = 0; i < rddm_image->entries; i++) {
+		cnss_pci_remove_dump_seg(pci_priv, dump_seg, CNSS_FW_RDDM, i,
+					 rddm_image->mhi_buf[i].buf,
+					 rddm_image->mhi_buf[i].dma_addr,
+					 rddm_image->mhi_buf[i].len);
+		dump_seg++;
+	}
+
+	for (i = 0, j = 0; i < plat_priv->fw_mem_seg_len; i++) {
+		if (fw_mem[i].type == CNSS_MEM_TYPE_DDR &&
+		    (fw_mem[i].attrs & DMA_ATTR_FORCE_CONTIGUOUS)) {
+			cnss_pci_remove_dump_seg(pci_priv, dump_seg,
+						 CNSS_FW_REMOTE_HEAP, j,
+						 fw_mem[i].va, fw_mem[i].pa,
+						 fw_mem[i].size);
+			dump_seg++;
+			j++;
+		} else if (fw_mem[i].type == CNSS_MEM_CAL_V01) {
+			cnss_pci_remove_dump_seg(pci_priv, dump_seg,
+						 CNSS_FW_CAL, j,
+						 fw_mem[i].va, fw_mem[i].pa,
+						 fw_mem[i].size);
+			dump_seg++;
+			j++;
+		}
+	}
+
+	plat_priv->ramdump_info_v2.dump_data.nentries = 0;
+	plat_priv->ramdump_info_v2.dump_data_valid = false;
+}
+
+void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return;
+	}
+
+	if (plat_priv->recovery_enabled)
+		cnss_pci_collect_host_dump_info(pci_priv);
+
+	/* Call recovery handler in the DRIVER_RECOVERY event context
+	 * instead of scheduling work. In that way complete recovery
+	 * will be done as part of DRIVER_RECOVERY event and get
+	 * serialized with other events.
+	 */
+	cnss_recovery_handler(plat_priv);
+}
+
+static int cnss_mhi_pm_runtime_get(struct mhi_controller *mhi_ctrl)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(mhi_ctrl->cntrl_dev);
+
+	return cnss_pci_pm_runtime_get(pci_priv, RTPM_ID_MHI);
+}
+
+static void cnss_mhi_pm_runtime_put_noidle(struct mhi_controller *mhi_ctrl)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(mhi_ctrl->cntrl_dev);
+
+	cnss_pci_pm_runtime_put_noidle(pci_priv, RTPM_ID_MHI);
+}
+
+void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv,
+				 char *prefix_name, char *name)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return;
+
+	plat_priv = pci_priv->plat_priv;
+
+	if (!plat_priv->use_fw_path_with_prefix) {
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN, "%s", name);
+		return;
+	}
+
+	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);
+		break;
+	case QCA6490_DEVICE_ID:
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
+			  QCA6490_PATH_PREFIX "%s", name);
+		break;
+	case KIWI_DEVICE_ID:
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
+			  KIWI_PATH_PREFIX "%s", name);
+		break;
+	case MANGO_DEVICE_ID:
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
+			  MANGO_PATH_PREFIX "%s", name);
+		break;
+	case PEACH_DEVICE_ID:
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN,
+			  PEACH_PATH_PREFIX "%s", name);
+		break;
+	default:
+		scnprintf(prefix_name, MAX_FIRMWARE_NAME_LEN, "%s", name);
+		break;
+	}
+
+	cnss_pr_dbg("FW name added with prefix: %s\n", prefix_name);
+}
+
+static int cnss_pci_update_fw_name(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+		if (plat_priv->device_version.major_version < FW_V2_NUMBER) {
+			cnss_pr_dbg("Device ID:version (0x%lx:%d) is not supported\n",
+				    pci_priv->device_id,
+				    plat_priv->device_version.major_version);
+			return -EINVAL;
+		}
+		cnss_pci_add_fw_prefix_name(pci_priv, plat_priv->firmware_name,
+					    FW_V2_FILE_NAME);
+		snprintf(plat_priv->fw_fallback_name, MAX_FIRMWARE_NAME_LEN,
+			 FW_V2_FILE_NAME);
+		break;
+	case QCA6490_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+		switch (plat_priv->device_version.major_version) {
+		case FW_V2_NUMBER:
+				cnss_pci_add_fw_prefix_name(pci_priv,
+							    plat_priv->firmware_name,
+							    FW_V2_FILE_NAME);
+				snprintf(plat_priv->fw_fallback_name,
+					 MAX_FIRMWARE_NAME_LEN,
+					 FW_V2_FILE_NAME);
+			break;
+		default:
+			cnss_pci_add_fw_prefix_name(pci_priv,
+						    plat_priv->firmware_name,
+						    DEFAULT_FW_FILE_NAME);
+			snprintf(plat_priv->fw_fallback_name,
+				 MAX_FIRMWARE_NAME_LEN,
+				 DEFAULT_FW_FILE_NAME);
+			break;
+		}
+		break;
+	case QCN7605_DEVICE_ID:
+		if (plat_priv->driver_mode == CNSS_FTM) {
+			cnss_pci_add_fw_prefix_name(pci_priv,
+						    plat_priv->firmware_name,
+						    DEFAULT_GENOA_FW_FTM_NAME);
+			snprintf(plat_priv->fw_fallback_name,
+				 MAX_FIRMWARE_NAME_LEN,
+				 DEFAULT_GENOA_FW_FTM_NAME);
+		} else {
+			cnss_pci_add_fw_prefix_name(pci_priv,
+						    plat_priv->firmware_name,
+						    DEFAULT_FW_FILE_NAME);
+			snprintf(plat_priv->fw_fallback_name,
+				 MAX_FIRMWARE_NAME_LEN,
+				 DEFAULT_FW_FILE_NAME);
+		}
+		break;
+	default:
+		cnss_pci_add_fw_prefix_name(pci_priv, plat_priv->firmware_name,
+					    DEFAULT_FW_FILE_NAME);
+		snprintf(plat_priv->fw_fallback_name, MAX_FIRMWARE_NAME_LEN,
+			 DEFAULT_FW_FILE_NAME);
+		break;
+	}
+
+	cnss_pr_dbg("FW name is %s, FW fallback name is %s\n",
+		    plat_priv->firmware_name, plat_priv->fw_fallback_name);
+
+	return 0;
+}
+
+static char *cnss_mhi_notify_status_to_str(enum mhi_callback status)
+{
+	switch (status) {
+	case MHI_CB_IDLE:
+		return "IDLE";
+	case MHI_CB_EE_RDDM:
+		return "RDDM";
+	case MHI_CB_SYS_ERROR:
+		return "SYS_ERROR";
+	case MHI_CB_FATAL_ERROR:
+		return "FATAL_ERROR";
+	case MHI_CB_EE_MISSION_MODE:
+		return "MISSION_MODE";
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC) && \
+(LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
+	case MHI_CB_FALLBACK_IMG:
+		return "FW_FALLBACK";
+#endif
+	default:
+		return "UNKNOWN";
+	}
+};
+
+static void cnss_dev_rddm_timeout_hdlr(struct timer_list *t)
+{
+	struct cnss_pci_data *pci_priv =
+		from_timer(pci_priv, t, dev_rddm_timer);
+	enum mhi_ee_type mhi_ee;
+
+	if (!pci_priv)
+		return;
+
+	cnss_fatal_err("Timeout waiting for RDDM notification\n");
+
+	mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
+	if (mhi_ee == MHI_EE_PBL)
+		cnss_pr_err("Device MHI EE is PBL, unable to collect dump\n");
+
+	if (mhi_ee == MHI_EE_RDDM) {
+		cnss_pr_info("Device MHI EE is RDDM, try to collect dump\n");
+		cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+				       CNSS_REASON_RDDM);
+	} else {
+		if (!cnss_pci_assert_host_sol(pci_priv))
+			return;
+		cnss_mhi_debug_reg_dump(pci_priv);
+		cnss_pci_bhi_debug_reg_dump(pci_priv);
+		cnss_pci_soc_scratch_reg_dump(pci_priv);
+		cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+				       CNSS_REASON_TIMEOUT);
+	}
+}
+
+static void cnss_boot_debug_timeout_hdlr(struct timer_list *t)
+{
+	struct cnss_pci_data *pci_priv =
+		from_timer(pci_priv, t, boot_debug_timer);
+
+	if (!pci_priv)
+		return;
+
+	if (cnss_pci_check_link_status(pci_priv))
+		return;
+
+	if (cnss_pci_is_device_down(&pci_priv->pci_dev->dev))
+		return;
+
+	if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state))
+		return;
+
+	if (cnss_mhi_scan_rddm_cookie(pci_priv, DEVICE_RDDM_COOKIE))
+		return;
+
+	cnss_pr_dbg("Dump MHI/PBL/SBL debug data every %ds during MHI power on\n",
+		    BOOT_DEBUG_TIMEOUT_MS / 1000);
+	cnss_mhi_debug_reg_dump(pci_priv);
+	cnss_pci_bhi_debug_reg_dump(pci_priv);
+	cnss_pci_soc_scratch_reg_dump(pci_priv);
+	cnss_pci_dump_bl_sram_mem(pci_priv);
+
+	mod_timer(&pci_priv->boot_debug_timer,
+		  jiffies + msecs_to_jiffies(BOOT_DEBUG_TIMEOUT_MS));
+}
+
+static int cnss_pci_handle_mhi_sys_err(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	cnss_ignore_qmi_failure(true);
+	set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+	del_timer(&plat_priv->fw_boot_timer);
+	reinit_completion(&pci_priv->wake_event_complete);
+	mod_timer(&pci_priv->dev_rddm_timer,
+		  jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
+	cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
+
+	return 0;
+}
+
+int cnss_pci_handle_dev_sol_irq(struct cnss_pci_data *pci_priv)
+{
+	return cnss_pci_handle_mhi_sys_err(pci_priv);
+}
+
+static void cnss_mhi_notify_status(struct mhi_controller *mhi_ctrl,
+				   enum mhi_callback reason)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(mhi_ctrl->cntrl_dev);
+	struct cnss_plat_data *plat_priv;
+	enum cnss_recovery_reason cnss_reason;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL");
+		return;
+	}
+
+	plat_priv = pci_priv->plat_priv;
+
+	if (reason != MHI_CB_IDLE)
+		cnss_pr_dbg("MHI status cb is called with reason %s(%d)\n",
+			    cnss_mhi_notify_status_to_str(reason), reason);
+
+	switch (reason) {
+	case MHI_CB_IDLE:
+	case MHI_CB_EE_MISSION_MODE:
+		return;
+	case MHI_CB_FATAL_ERROR:
+		cnss_ignore_qmi_failure(true);
+		set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+		del_timer(&plat_priv->fw_boot_timer);
+		cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
+		cnss_reason = CNSS_REASON_DEFAULT;
+		break;
+	case MHI_CB_SYS_ERROR:
+		cnss_pci_handle_mhi_sys_err(pci_priv);
+		return;
+	case MHI_CB_EE_RDDM:
+		cnss_ignore_qmi_failure(true);
+		set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+		del_timer(&plat_priv->fw_boot_timer);
+		del_timer(&pci_priv->dev_rddm_timer);
+		cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
+		cnss_reason = CNSS_REASON_RDDM;
+		break;
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC) && \
+(LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
+	case MHI_CB_FALLBACK_IMG:
+		plat_priv->use_fw_path_with_prefix = false;
+		cnss_pci_update_fw_name(pci_priv);
+		return;
+#endif
+
+	default:
+		cnss_pr_err("Unsupported MHI status cb reason: %d\n", reason);
+		return;
+	}
+
+	cnss_schedule_recovery(&pci_priv->pci_dev->dev, cnss_reason);
+}
+
+static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv)
+{
+	int ret, num_vectors, i;
+	u32 user_base_data, base_vector;
+	int *irq;
+	unsigned int msi_data;
+	bool is_one_msi = false;
+
+	ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+					   MHI_MSI_NAME, &num_vectors,
+					   &user_base_data, &base_vector);
+	if (ret)
+		return ret;
+
+	if (cnss_pci_is_one_msi(pci_priv)) {
+		is_one_msi = true;
+		num_vectors = cnss_pci_get_one_msi_mhi_irq_array_size(pci_priv);
+	}
+	cnss_pr_dbg("Number of assigned MSI for MHI is %d, base vector is %d\n",
+		    num_vectors, base_vector);
+
+	irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL);
+	if (!irq)
+		return -ENOMEM;
+
+	for (i = 0; i < num_vectors; i++) {
+		msi_data = base_vector;
+		if (!is_one_msi)
+			msi_data += i;
+		irq[i] = cnss_get_msi_irq(&pci_priv->pci_dev->dev, msi_data);
+	}
+
+	pci_priv->mhi_ctrl->irq = irq;
+	pci_priv->mhi_ctrl->nr_irqs = num_vectors;
+
+	return 0;
+}
+
+static int cnss_mhi_bw_scale(struct mhi_controller *mhi_ctrl,
+			     struct mhi_link_info *link_info)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(mhi_ctrl->cntrl_dev);
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	int ret = 0;
+
+	if (plat_priv->pcie_switch_type == PCIE_SWITCH_NTN3) {
+		ret = cnss_pci_dsp_link_retrain(pci_priv,
+						link_info->target_link_speed);
+		return ret;
+	}
+
+	cnss_pr_dbg("Setting link speed:0x%x, width:0x%x\n",
+		    link_info->target_link_speed,
+		    link_info->target_link_width);
+
+	/* It has to set target link speed here before setting link bandwidth
+	 * when device requests link speed change. This can avoid setting link
+	 * bandwidth getting rejected if requested link speed is higher than
+	 * current one.
+	 */
+	ret = cnss_pci_set_max_link_speed(pci_priv, plat_priv->rc_num,
+					  link_info->target_link_speed);
+	if (ret)
+		cnss_pr_err("Failed to set target link speed to 0x%x, err = %d\n",
+			    link_info->target_link_speed, ret);
+
+	ret = cnss_pci_set_link_bandwidth(pci_priv,
+					  link_info->target_link_speed,
+					  link_info->target_link_width);
+
+	if (ret) {
+		cnss_pr_err("Failed to set link bandwidth, err = %d\n", ret);
+		return ret;
+	}
+
+	pci_priv->def_link_speed = link_info->target_link_speed;
+	pci_priv->def_link_width = link_info->target_link_width;
+
+	return 0;
+}
+
+static int cnss_mhi_read_reg(struct mhi_controller *mhi_ctrl,
+			     void __iomem *addr, u32 *out)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(mhi_ctrl->cntrl_dev);
+
+	u32 tmp = readl_relaxed(addr);
+
+	/* Unexpected value, query the link status */
+	if (PCI_INVALID_READ(tmp) &&
+	    cnss_pci_check_link_status(pci_priv))
+		return -EIO;
+
+	*out = tmp;
+
+	return 0;
+}
+
+static void cnss_mhi_write_reg(struct mhi_controller *mhi_ctrl,
+			       void __iomem *addr, u32 val)
+{
+	writel_relaxed(val, addr);
+}
+
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
+/**
+ * __cnss_get_mhi_soc_info - Get SoC info before registering mhi controller
+ * @mhi_ctrl: MHI controller
+ *
+ * Return: 0 for success, error code on failure
+ */
+static inline int __cnss_get_mhi_soc_info(struct mhi_controller *mhi_ctrl)
+{
+	return mhi_get_soc_info(mhi_ctrl);
+}
+#else
+#define SOC_HW_VERSION_OFFS (0x224)
+#define SOC_HW_VERSION_FAM_NUM_BMSK (0xF0000000)
+#define SOC_HW_VERSION_FAM_NUM_SHFT (28)
+#define SOC_HW_VERSION_DEV_NUM_BMSK (0x0FFF0000)
+#define SOC_HW_VERSION_DEV_NUM_SHFT (16)
+#define SOC_HW_VERSION_MAJOR_VER_BMSK (0x0000FF00)
+#define SOC_HW_VERSION_MAJOR_VER_SHFT (8)
+#define SOC_HW_VERSION_MINOR_VER_BMSK (0x000000FF)
+#define SOC_HW_VERSION_MINOR_VER_SHFT (0)
+
+static int __cnss_get_mhi_soc_info(struct mhi_controller *mhi_ctrl)
+{
+	u32 soc_info;
+	int ret;
+
+	ret = mhi_ctrl->read_reg(mhi_ctrl,
+				 mhi_ctrl->regs + SOC_HW_VERSION_OFFS,
+				 &soc_info);
+	if (ret)
+		return ret;
+
+	mhi_ctrl->family_number = (soc_info & SOC_HW_VERSION_FAM_NUM_BMSK) >>
+		SOC_HW_VERSION_FAM_NUM_SHFT;
+	mhi_ctrl->device_number = (soc_info & SOC_HW_VERSION_DEV_NUM_BMSK) >>
+		SOC_HW_VERSION_DEV_NUM_SHFT;
+	mhi_ctrl->major_version = (soc_info & SOC_HW_VERSION_MAJOR_VER_BMSK) >>
+		SOC_HW_VERSION_MAJOR_VER_SHFT;
+	mhi_ctrl->minor_version = (soc_info & SOC_HW_VERSION_MINOR_VER_BMSK) >>
+		SOC_HW_VERSION_MINOR_VER_SHFT;
+	return 0;
+}
+#endif
+
+static int cnss_get_mhi_soc_info(struct cnss_plat_data *plat_priv,
+				 struct mhi_controller *mhi_ctrl)
+{
+	int ret = 0;
+
+	ret = __cnss_get_mhi_soc_info(mhi_ctrl);
+	if (ret) {
+		cnss_pr_err("failed to get mhi soc info, ret %d\n", ret);
+		goto exit;
+	}
+
+	plat_priv->device_version.family_number = mhi_ctrl->family_number;
+	plat_priv->device_version.device_number = mhi_ctrl->device_number;
+	plat_priv->device_version.major_version = mhi_ctrl->major_version;
+	plat_priv->device_version.minor_version = mhi_ctrl->minor_version;
+
+	cnss_pr_dbg("Get device version info, family number: 0x%x, device number: 0x%x, major version: 0x%x, minor version: 0x%x\n",
+		    plat_priv->device_version.family_number,
+		    plat_priv->device_version.device_number,
+		    plat_priv->device_version.major_version,
+		    plat_priv->device_version.minor_version);
+
+	/* Only keep lower 4 bits as real device major version */
+	plat_priv->device_version.major_version &= DEVICE_MAJOR_VERSION_MASK;
+
+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;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct mhi_controller *mhi_ctrl;
+	phys_addr_t bar_start;
+	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;
+
+	mhi_ctrl = mhi_alloc_controller();
+	if (!mhi_ctrl) {
+		cnss_pr_err("Invalid MHI controller context\n");
+		return -EINVAL;
+	}
+
+	pci_priv->mhi_ctrl = mhi_ctrl;
+	mhi_ctrl->cntrl_dev = &pci_dev->dev;
+
+	mhi_ctrl->fw_image = plat_priv->firmware_name;
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC) && \
+(LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0))
+	mhi_ctrl->fallback_fw_image = plat_priv->fw_fallback_name;
+#endif
+
+	mhi_ctrl->regs = pci_priv->bar;
+	mhi_ctrl->reg_len = pci_resource_len(pci_priv->pci_dev, PCI_BAR_NUM);
+	bar_start = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM);
+	cnss_pr_dbg("BAR starts at %pa, length is %x\n",
+		    &bar_start, mhi_ctrl->reg_len);
+
+	ret = cnss_pci_get_mhi_msi(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get MSI for MHI, err = %d\n", ret);
+		goto free_mhi_ctrl;
+	}
+
+	if (cnss_pci_is_one_msi(pci_priv))
+		mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
+
+	if (pci_priv->smmu_s1_enable) {
+		mhi_ctrl->iova_start = pci_priv->smmu_iova_start;
+		mhi_ctrl->iova_stop = pci_priv->smmu_iova_start +
+					pci_priv->smmu_iova_len;
+	} else {
+		mhi_ctrl->iova_start = 0;
+		mhi_ctrl->iova_stop = pci_priv->dma_bit_mask;
+	}
+
+	mhi_ctrl->status_cb = cnss_mhi_notify_status;
+	mhi_ctrl->runtime_get = cnss_mhi_pm_runtime_get;
+	mhi_ctrl->runtime_put = cnss_mhi_pm_runtime_put_noidle;
+	mhi_ctrl->read_reg = cnss_mhi_read_reg;
+	mhi_ctrl->write_reg = cnss_mhi_write_reg;
+
+	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;
+
+	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;
+
+	ret = cnss_get_mhi_soc_info(plat_priv, mhi_ctrl);
+	if (ret)
+		goto free_mhi_irq;
+
+	/* 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)) {
+		if (plat_priv->device_id == QCN7605_DEVICE_ID)
+			cnss_mhi_config = &cnss_mhi_config_genoa;
+		else
+			cnss_mhi_config = &cnss_mhi_config_no_satellite;
+	}
+
+	/* DIAG no longer supported on PEACH and later chipset */
+	if (plat_priv->device_id >= PEACH_DEVICE_ID) {
+		cnss_mhi_config = &cnss_mhi_config_no_diag;
+	}
+
+	mhi_ctrl->tme_supported_image = cnss_is_tme_supported(pci_priv);
+
+	ret = mhi_register_controller(mhi_ctrl, cnss_mhi_config);
+	if (ret) {
+		cnss_pr_err("Failed to register to MHI bus, err = %d\n", ret);
+		goto free_mhi_irq;
+	}
+
+	/* MHI satellite driver only needs to connect when DRV is supported */
+	if (cnss_pci_get_drv_supported(pci_priv))
+		cnss_mhi_controller_set_base(pci_priv, bar_start);
+
+	cnss_get_bwscal_info(plat_priv);
+	cnss_pr_dbg("no_bwscale: %d\n", plat_priv->no_bwscale);
+
+	/* BW scale CB needs to be set after registering MHI per requirement */
+	if (!plat_priv->no_bwscale)
+		cnss_mhi_controller_set_bw_scale_cb(pci_priv,
+						    cnss_mhi_bw_scale);
+
+	ret = cnss_pci_update_fw_name(pci_priv);
+	if (ret)
+		goto unreg_mhi;
+
+	return 0;
+
+unreg_mhi:
+	mhi_unregister_controller(mhi_ctrl);
+free_mhi_irq:
+	kfree(mhi_ctrl->irq);
+free_mhi_ctrl:
+	mhi_free_controller(mhi_ctrl);
+
+	return ret;
+}
+
+static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv)
+{
+	struct mhi_controller *mhi_ctrl = pci_priv->mhi_ctrl;
+
+	if (pci_priv->device_id == QCA6174_DEVICE_ID)
+		return;
+
+	mhi_unregister_controller(mhi_ctrl);
+	kfree(mhi_ctrl->irq);
+	mhi_ctrl->irq = NULL;
+	mhi_free_controller(mhi_ctrl);
+	pci_priv->mhi_ctrl = NULL;
+}
+
+static void cnss_pci_config_regs(struct cnss_pci_data *pci_priv)
+{
+	switch (pci_priv->device_id) {
+	case QCA6390_DEVICE_ID:
+		pci_priv->misc_reg_dev_mask = REG_MASK_QCA6390;
+		pci_priv->wcss_reg = wcss_reg_access_seq;
+		pci_priv->pcie_reg = pcie_reg_access_seq;
+		pci_priv->wlaon_reg = wlaon_reg_access_seq;
+		pci_priv->syspm_reg = syspm_reg_access_seq;
+
+		/* Configure WDOG register with specific value so that we can
+		 * know if HW is in the process of WDOG reset recovery or not
+		 * when reading the registers.
+		 */
+		cnss_pci_reg_write
+		(pci_priv,
+		QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG,
+		QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG_VAL);
+		break;
+	case QCA6490_DEVICE_ID:
+		pci_priv->misc_reg_dev_mask = REG_MASK_QCA6490;
+		pci_priv->wlaon_reg = wlaon_reg_access_seq;
+		break;
+	default:
+		return;
+	}
+}
+
+#if !IS_ENABLED(CONFIG_ARCH_QCOM)
+static int cnss_pci_of_reserved_mem_device_init(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+static irqreturn_t cnss_pci_wake_handler(int irq, void *data)
+{
+	struct cnss_pci_data *pci_priv = data;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	enum rpm_status status;
+	struct device *dev;
+
+	pci_priv->wake_counter++;
+	cnss_pr_dbg("WLAN PCI wake IRQ (%u) is asserted #%u\n",
+		    pci_priv->wake_irq, pci_priv->wake_counter);
+
+	/* Make sure abort current suspend */
+	cnss_pm_stay_awake(plat_priv);
+	cnss_pm_relax(plat_priv);
+	/* Above two pm* API calls will abort system suspend only when
+	 * plat_dev->dev->ws is initiated by device_init_wakeup() API, and
+	 * calling pm_system_wakeup() is just to guarantee system suspend
+	 * can be aborted if it is not initiated in any case.
+	 */
+	pm_system_wakeup();
+
+	dev = &pci_priv->pci_dev->dev;
+	status = dev->power.runtime_status;
+
+	if ((cnss_pci_get_monitor_wake_intr(pci_priv) &&
+	     cnss_pci_get_auto_suspended(pci_priv)) ||
+	    (status == RPM_SUSPENDING || status == RPM_SUSPENDED)) {
+		cnss_pci_set_monitor_wake_intr(pci_priv, false);
+		cnss_pci_pm_request_resume(pci_priv);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * cnss_pci_wake_gpio_init() - Setup PCI wake GPIO for WLAN
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function initializes WLAN PCI wake GPIO and corresponding
+ * interrupt. It should be used in non-MSM platforms whose PCIe
+ * root complex driver doesn't handle the GPIO.
+ *
+ * Return: 0 for success or skip, negative value for error
+ */
+static int cnss_pci_wake_gpio_init(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	int ret = 0;
+
+	pci_priv->wake_gpio = of_get_named_gpio(dev->of_node,
+						"wlan-pci-wake-gpio", 0);
+	if (pci_priv->wake_gpio < 0)
+		goto out;
+
+	cnss_pr_dbg("Get PCI wake GPIO (%d) from device node\n",
+		    pci_priv->wake_gpio);
+
+	ret = gpio_request(pci_priv->wake_gpio, "wlan_pci_wake_gpio");
+	if (ret) {
+		cnss_pr_err("Failed to request PCI wake GPIO, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	gpio_direction_input(pci_priv->wake_gpio);
+	pci_priv->wake_irq = gpio_to_irq(pci_priv->wake_gpio);
+
+	ret = request_irq(pci_priv->wake_irq, cnss_pci_wake_handler,
+			  IRQF_TRIGGER_FALLING, "wlan_pci_wake_irq", pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to request PCI wake IRQ, err = %d\n", ret);
+		goto free_gpio;
+	}
+
+	ret = enable_irq_wake(pci_priv->wake_irq);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCI wake IRQ, err = %d\n", ret);
+		goto free_irq;
+	}
+
+	return 0;
+
+free_irq:
+	free_irq(pci_priv->wake_irq, pci_priv);
+free_gpio:
+	gpio_free(pci_priv->wake_gpio);
+out:
+	return ret;
+}
+
+static void cnss_pci_wake_gpio_deinit(struct cnss_pci_data *pci_priv)
+{
+	if (pci_priv->wake_gpio < 0)
+		return;
+
+	disable_irq_wake(pci_priv->wake_irq);
+	free_irq(pci_priv->wake_irq, pci_priv);
+	gpio_free(pci_priv->wake_gpio);
+}
+#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
+
+void cnss_pci_of_switch_type_init(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	int ret;
+
+	if (dev && dev->of_node) {
+		ret = of_property_read_u32(dev->of_node,
+					   "qcom,pcie-switch-type",
+					   &plat_priv->pcie_switch_type);
+		if (ret)
+			plat_priv->pcie_switch_type = 0;
+	} else {
+		cnss_pr_err("device or node is not available.");
+	}
+	cnss_pr_dbg("pcie_switch_type is %d", plat_priv->pcie_switch_type);
+}
+
+/* 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
+ * from pci_dev_pm_ops.
+ */
+static struct dev_pm_domain cnss_pm_domain = {
+	.ops = {
+		SET_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend, cnss_pci_resume)
+		SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend_noirq,
+					      cnss_pci_resume_noirq)
+		SET_RUNTIME_PM_OPS(cnss_pci_runtime_suspend,
+				   cnss_pci_runtime_resume,
+				   cnss_pci_runtime_idle)
+	}
+};
+
+static int cnss_pci_get_dev_cfg_node(struct cnss_plat_data *plat_priv)
+{
+	struct device_node *child;
+	u32 id, i;
+	int id_n, ret;
+
+	if (plat_priv->dt_type != CNSS_DTT_MULTIEXCHG)
+		return 0;
+
+	if (!plat_priv->device_id) {
+		cnss_pr_err("Invalid device id\n");
+		return -EINVAL;
+	}
+
+	for_each_available_child_of_node(plat_priv->plat_dev->dev.of_node,
+					 child) {
+		if (strcmp(child->name, "chip_cfg"))
+			continue;
+
+		id_n = of_property_count_u32_elems(child, "supported-ids");
+		if (id_n <= 0) {
+			cnss_pr_err("Device id is NOT set\n");
+			return -EINVAL;
+		}
+
+		for (i = 0; i < id_n; i++) {
+			ret = of_property_read_u32_index(child,
+							 "supported-ids",
+							 i, &id);
+			if (ret) {
+				cnss_pr_err("Failed to read supported ids\n");
+				return -EINVAL;
+			}
+
+			if (id == plat_priv->device_id) {
+				plat_priv->dev_node = child;
+				cnss_pr_dbg("got node[%s@%d] for device[0x%x]\n",
+					    child->name, i, id);
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+#ifdef CONFIG_CNSS2_CONDITIONAL_POWEROFF
+static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	bool suspend_pwroff;
+
+	switch (pci_dev->device) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+		suspend_pwroff = false;
+		break;
+	default:
+		suspend_pwroff = true;
+	}
+
+	return suspend_pwroff;
+}
+#else
+static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	return true;
+}
+#endif
+
+#ifdef CONFIG_CNSS2_ENUM_WITH_LOW_SPEED
+static void
+cnss_pci_downgrade_rc_speed(struct cnss_plat_data *plat_priv, u32 rc_num)
+{
+	int ret;
+
+	ret = cnss_pci_set_max_link_speed(plat_priv->bus_priv, rc_num,
+					  PCI_EXP_LNKSTA_CLS_2_5GB);
+	if (ret)
+		cnss_pr_err("Failed to set max PCIe RC%x link speed to Gen1, err = %d\n",
+			     rc_num, ret);
+}
+
+static void
+cnss_pci_restore_rc_speed(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+	u16 link_speed;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	switch (pci_priv->device_id) {
+	case QCN7605_DEVICE_ID:
+		/* do nothing, keep Gen1*/
+		return;
+	case QCA6490_DEVICE_ID:
+		/* restore to Gen2 */
+		link_speed = PCI_EXP_LNKSTA_CLS_5_0GB;
+		break;
+	default:
+		/* The request 0 will reset maximum GEN speed to default */
+		link_speed = 0;
+		break;
+	}
+
+	ret = cnss_pci_set_max_link_speed(pci_priv, plat_priv->rc_num, link_speed);
+	if (ret)
+		cnss_pr_err("Failed to set max PCIe RC%x link speed to %d, err = %d\n",
+			    plat_priv->rc_num, link_speed, ret);
+}
+
+static void
+cnss_pci_link_retrain_trigger(struct cnss_pci_data *pci_priv)
+{
+	int ret;
+
+	/* suspend/resume will trigger retain to re-establish link speed */
+	ret = cnss_suspend_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+
+	cnss_pci_get_link_status(pci_priv);
+}
+#else
+static void
+cnss_pci_downgrade_rc_speed(struct cnss_plat_data *plat_priv, u32 rc_num)
+{
+}
+
+static void
+cnss_pci_restore_rc_speed(struct cnss_pci_data *pci_priv)
+{
+}
+
+static void
+cnss_pci_link_retrain_trigger(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+
+static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	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)
+			cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+				    ret);
+		cnss_power_off_device(plat_priv);
+	} else {
+		cnss_pr_dbg("bus suspend and dev power off disabled for device [0x%x]\n",
+			    pci_dev->device);
+		cnss_pci_link_retrain_trigger(pci_priv);
+	}
+}
+
+static int cnss_pci_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv;
+	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 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) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	pci_priv->pci_link_state = PCI_LINK_UP;
+	pci_priv->plat_priv = plat_priv;
+	pci_priv->pci_dev = pci_dev;
+	pci_priv->pci_device_id = id;
+	pci_priv->device_id = pci_dev->device;
+	cnss_set_pci_priv(pci_dev, pci_priv);
+	plat_priv->device_id = pci_dev->device;
+	plat_priv->bus_priv = pci_priv;
+	mutex_init(&pci_priv->bus_lock);
+	if (plat_priv->use_pm_domain)
+		dev->pm_domain = &cnss_pm_domain;
+
+	cnss_pci_restore_rc_speed(pci_priv);
+
+	ret = cnss_pci_get_dev_cfg_node(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get device cfg node, err = %d\n", ret);
+		goto reset_ctx;
+	}
+
+	cnss_get_sleep_clk_supported(plat_priv);
+
+	ret = cnss_dev_specific_power_on(plat_priv);
+	if (ret < 0)
+		goto reset_ctx;
+
+	cnss_pci_of_reserved_mem_device_init(pci_priv);
+
+	ret = cnss_register_subsys(plat_priv);
+	if (ret)
+		goto reset_ctx;
+
+	ret = cnss_register_ramdump(plat_priv);
+	if (ret)
+		goto unregister_subsys;
+
+	ret = cnss_pci_init_smmu(pci_priv);
+	if (ret)
+		goto unregister_ramdump;
+
+	/* update drv support flag */
+	cnss_pci_update_drv_supported(pci_priv);
+
+	cnss_update_supported_link_info(pci_priv);
+
+	init_completion(&pci_priv->wake_event_complete);
+
+	ret = cnss_reg_pci_event(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to register PCI event, err = %d\n", ret);
+		goto deinit_smmu;
+	}
+
+	ret = cnss_pci_enable_bus(pci_priv);
+	if (ret)
+		goto dereg_pci_event;
+
+	ret = cnss_pci_enable_msi(pci_priv);
+	if (ret)
+		goto disable_bus;
+
+	ret = cnss_pci_register_mhi(pci_priv);
+	if (ret)
+		goto disable_msi;
+
+	switch (pci_dev->device) {
+	case QCA6174_DEVICE_ID:
+		pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
+				     &pci_priv->revision_id);
+		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:
+		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,
+			    cnss_boot_debug_timeout_hdlr, 0);
+		INIT_DELAYED_WORK(&pci_priv->time_sync_work,
+				  cnss_pci_time_sync_work_hdlr);
+		cnss_pci_get_link_status(pci_priv);
+		cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, false);
+		cnss_pci_wake_gpio_init(pci_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown PCI device found: 0x%x\n",
+			    pci_dev->device);
+		ret = -ENODEV;
+		goto unreg_mhi;
+	}
+
+	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;
+
+unreg_mhi:
+	cnss_pci_unregister_mhi(pci_priv);
+disable_msi:
+	cnss_pci_disable_msi(pci_priv);
+disable_bus:
+	cnss_pci_disable_bus(pci_priv);
+dereg_pci_event:
+	cnss_dereg_pci_event(pci_priv);
+deinit_smmu:
+	cnss_pci_deinit_smmu(pci_priv);
+unregister_ramdump:
+	cnss_unregister_ramdump(plat_priv);
+unregister_subsys:
+	cnss_unregister_subsys(plat_priv);
+reset_ctx:
+	plat_priv->bus_priv = NULL;
+out:
+	return ret;
+}
+
+static void cnss_pci_remove(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(&pci_dev->dev);
+
+	clear_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state);
+	cnss_pci_unregister_driver_hdlr(pci_priv);
+	cnss_pci_free_aux_mem(pci_priv);
+	cnss_pci_free_tme_lite_mem(pci_priv);
+	cnss_pci_free_tme_opt_file_mem(pci_priv);
+	cnss_pci_free_m3_mem(pci_priv);
+	cnss_pci_free_fw_mem(pci_priv);
+	cnss_pci_free_qdss_mem(pci_priv);
+
+	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:
+	case PEACH_DEVICE_ID:
+		cnss_pci_wake_gpio_deinit(pci_priv);
+		del_timer(&pci_priv->boot_debug_timer);
+		del_timer(&pci_priv->dev_rddm_timer);
+		break;
+	default:
+		break;
+	}
+
+	cnss_pci_unregister_mhi(pci_priv);
+	cnss_pci_disable_msi(pci_priv);
+	cnss_pci_disable_bus(pci_priv);
+	cnss_dereg_pci_event(pci_priv);
+	cnss_pci_deinit_smmu(pci_priv);
+	if (plat_priv) {
+		cnss_unregister_ramdump(plat_priv);
+		cnss_unregister_subsys(plat_priv);
+		plat_priv->bus_priv = NULL;
+	} else {
+		cnss_pr_err("Plat_priv is null, Unable to unregister ramdump,subsys\n");
+	}
+}
+
+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 },
+	{ PEACH_VENDOR_ID, PEACH_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_pci_id_table);
+
+static const struct dev_pm_ops cnss_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend, cnss_pci_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend_noirq,
+				      cnss_pci_resume_noirq)
+	SET_RUNTIME_PM_OPS(cnss_pci_runtime_suspend, cnss_pci_runtime_resume,
+			   cnss_pci_runtime_idle)
+};
+
+static struct pci_driver cnss_pci_driver = {
+	.name     = "cnss_pci",
+	.id_table = cnss_pci_id_table,
+	.probe    = cnss_pci_probe,
+	.remove   = cnss_pci_remove,
+	.driver = {
+		.pm = &cnss_pm_ops,
+	},
+};
+
+static int cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
+{
+	int ret, retry = 0;
+
+	/* Always set initial target PCIe link speed to Gen2 for QCA6490 device
+	 * since there may be link issues if it boots up with Gen3 link speed.
+	 * Device is able to change it later at any time. It will be rejected
+	 * if requested speed is higher than the one specified in PCIe DT.
+	 */
+	if (plat_priv->device_id == QCA6490_DEVICE_ID) {
+		ret = cnss_pci_set_max_link_speed(plat_priv->bus_priv, rc_num,
+						  PCI_EXP_LNKSTA_CLS_5_0GB);
+		if (ret && ret != -EPROBE_DEFER)
+			cnss_pr_err("Failed to set max PCIe RC%x link speed to Gen2, err = %d\n",
+				    rc_num, ret);
+	} else {
+		cnss_pci_downgrade_rc_speed(plat_priv, rc_num);
+	}
+
+	cnss_pr_dbg("Trying to enumerate with PCIe RC%x\n", rc_num);
+retry:
+	ret = _cnss_pci_enumerate(plat_priv, rc_num);
+	if (ret) {
+		if (ret == -EPROBE_DEFER) {
+			cnss_pr_dbg("PCIe RC driver is not ready, defer probe\n");
+			goto out;
+		}
+		cnss_pr_err("Failed to enable PCIe RC%x, err = %d\n",
+			    rc_num, ret);
+		if (retry++ < LINK_TRAINING_RETRY_MAX_TIMES) {
+			cnss_pr_dbg("Retry PCI link training #%d\n", retry);
+			goto retry;
+		} else {
+			goto out;
+		}
+	}
+
+	plat_priv->rc_num = rc_num;
+
+out:
+	return ret;
+}
+
+int cnss_pci_init(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	const __be32 *prop;
+	int ret = 0, prop_len = 0, rc_count, i;
+
+	prop = of_get_property(dev->of_node, "qcom,wlan-rc-num", &prop_len);
+	if (!prop || !prop_len) {
+		cnss_pr_err("Failed to get PCIe RC number from DT\n");
+		goto out;
+	}
+
+	rc_count = prop_len / sizeof(__be32);
+	for (i = 0; i < rc_count; i++) {
+		ret = cnss_pci_enumerate(plat_priv, be32_to_cpup(&prop[i]));
+		if (!ret)
+			break;
+		else if (ret == -EPROBE_DEFER || (ret && i == rc_count - 1))
+			goto out;
+	}
+
+	ret = cnss_try_suspend(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to suspend, ret: %d\n", ret);
+		goto out;
+	}
+
+	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;
+
+unreg_pci:
+	pci_unregister_driver(&cnss_pci_driver);
+out:
+	return ret;
+}
+
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (cnss_driver_registered) {
+		pci_unregister_driver(&cnss_pci_driver);
+		cnss_driver_registered = false;
+	}
+}

+ 350 - 0
qcom/opensource/wlan/platform/cnss2/pci.h

@@ -0,0 +1,350 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CNSS_PCI_H
+#define _CNSS_PCI_H
+
+#include <linux/cma.h>
+#include <linux/iommu.h>
+#include <linux/qcom-iommu-util.h>
+#include <linux/mhi.h>
+#if IS_ENABLED(CONFIG_MHI_BUS_MISC)
+#include <linux/mhi_misc.h>
+#endif
+#if IS_ENABLED(CONFIG_PCI_MSM)
+#include <linux/msm_pcie.h>
+#endif
+#include <linux/of_reserved_mem.h>
+#include <linux/pci.h>
+#include <linux/sched_clock.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
+#include <linux/sched/clock.h>
+#endif
+
+
+#include "main.h"
+
+#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
+
+#define CNSS_MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || \
+				      ee == MHI_EE_WFW || \
+				      ee == MHI_EE_FP)
+
+#define PCI_DSP_LINK_ENABLE                     1
+#define PCI_DSP_LINK_DISABLE                    0
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+#define DSP_LINK_ENABLE_DELAY_TIME_US_MIN       (25000)
+#define DSP_LINK_ENABLE_DELAY_TIME_US_MAX       (25100)
+#define DSP_LINK_ENABLE_RETRY_COUNT_MAX         (3)
+#endif
+
+enum cnss_mhi_state {
+	CNSS_MHI_INIT,
+	CNSS_MHI_DEINIT,
+	CNSS_MHI_POWER_ON,
+	CNSS_MHI_POWERING_OFF,
+	CNSS_MHI_POWER_OFF,
+	CNSS_MHI_FORCE_POWER_OFF,
+	CNSS_MHI_SUSPEND,
+	CNSS_MHI_RESUME,
+	CNSS_MHI_TRIGGER_RDDM,
+	CNSS_MHI_RDDM,
+	CNSS_MHI_RDDM_DONE,
+};
+
+enum pci_link_status {
+	PCI_GEN1,
+	PCI_GEN2,
+	PCI_DEF,
+};
+
+enum  cnss_rtpm_id {
+	RTPM_ID_CNSS,
+	RTPM_ID_MHI,
+	RTPM_ID_MAX,
+};
+
+enum cnss_pci_reg_dev_mask {
+	REG_MASK_QCA6390,
+	REG_MASK_QCA6490,
+	REG_MASK_KIWI,
+	REG_MASK_MANGO,
+	REG_MASK_PEACH,
+};
+
+enum cnss_smmu_fault_time {
+	SMMU_CB_ENTRY,
+	SMMU_CB_DOORBELL_RING,
+	SMMU_CB_EXIT,
+	SMMU_CB_MAX,
+};
+
+struct cnss_msi_user {
+	char *name;
+	int num_vectors;
+	u32 base_vector;
+};
+
+struct cnss_msi_config {
+	int total_vectors;
+	int total_users;
+	struct cnss_msi_user *users;
+};
+
+struct cnss_pci_reg {
+	char *name;
+	u32 offset;
+};
+
+struct cnss_pci_debug_reg {
+	u32 offset;
+	u32 val;
+};
+
+struct cnss_misc_reg {
+	unsigned long dev_mask;
+	u8 wr;
+	u32 offset;
+	u32 val;
+};
+
+struct cnss_pm_stats {
+	atomic_t runtime_get;
+	atomic_t runtime_put;
+	atomic_t runtime_get_id[RTPM_ID_MAX];
+	atomic_t runtime_put_id[RTPM_ID_MAX];
+	u64 runtime_get_timestamp_id[RTPM_ID_MAX];
+	u64 runtime_put_timestamp_id[RTPM_ID_MAX];
+};
+
+struct cnss_print_optimize {
+	int msi_log_chk[MSI_USERS];
+	int msi_addr_chk;
+};
+
+struct cnss_pci_data {
+	struct pci_dev *pci_dev;
+	struct cnss_plat_data *plat_priv;
+	const struct pci_device_id *pci_device_id;
+	u32 device_id;
+	u16 revision_id;
+	u64 dma_bit_mask;
+	struct cnss_wlan_driver *driver_ops;
+	u8 pci_link_state;
+	u8 pci_link_down_ind;
+	struct pci_saved_state *saved_state;
+	struct pci_saved_state *default_state;
+#if IS_ENABLED(CONFIG_PCI_MSM)
+	struct msm_pcie_register_event msm_pci_event;
+#endif
+	struct cnss_pm_stats pm_stats;
+	atomic_t auto_suspended;
+	atomic_t drv_connected;
+	u8 drv_connected_last;
+	u32 qmi_send_usage_count;
+	u16 def_link_speed;
+	u16 def_link_width;
+	u16 cur_link_speed;
+	int wake_gpio;
+	int wake_irq;
+	u32 wake_counter;
+	u8 monitor_wake_intr;
+	struct iommu_domain *iommu_domain;
+	u8 smmu_s1_enable;
+	dma_addr_t smmu_iova_start;
+	size_t smmu_iova_len;
+	dma_addr_t smmu_iova_ipa_start;
+	dma_addr_t smmu_iova_ipa_current;
+	size_t smmu_iova_ipa_len;
+	void __iomem *bar;
+	struct cnss_msi_config *msi_config;
+	u32 msi_ep_base_data;
+	u32 msix_addr;
+	struct mhi_controller *mhi_ctrl;
+	unsigned long mhi_state;
+	u32 remap_window;
+	struct completion wake_event_complete;
+	struct timer_list dev_rddm_timer;
+	struct timer_list boot_debug_timer;
+	struct delayed_work time_sync_work;
+	u8 disable_pc;
+	struct mutex bus_lock; /* mutex for suspend and resume bus */
+	struct cnss_pci_debug_reg *debug_reg;
+	struct cnss_misc_reg *wcss_reg;
+	struct cnss_misc_reg *pcie_reg;
+	struct cnss_misc_reg *wlaon_reg;
+	struct cnss_misc_reg *syspm_reg;
+	unsigned long misc_reg_dev_mask;
+	u8 iommu_geometry;
+	bool drv_supported;
+	bool is_smmu_fault;
+	unsigned long long smmu_fault_timestamp[SMMU_CB_MAX];
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+	bool pci_dsp_link_status;
+#endif
+};
+
+static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
+{
+	pci_set_drvdata(pci_dev, data);
+}
+
+static inline struct cnss_pci_data *cnss_get_pci_priv(struct pci_dev *pci_dev)
+{
+	return pci_get_drvdata(pci_dev);
+}
+
+static inline struct cnss_plat_data *cnss_pci_priv_to_plat_priv(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return pci_priv->plat_priv;
+}
+
+static inline void cnss_pci_set_monitor_wake_intr(void *bus_priv, bool val)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	pci_priv->monitor_wake_intr = val;
+}
+
+static inline bool cnss_pci_get_monitor_wake_intr(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return pci_priv->monitor_wake_intr;
+}
+
+static inline void cnss_pci_set_auto_suspended(void *bus_priv, int val)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	atomic_set(&pci_priv->auto_suspended, val);
+}
+
+static inline int cnss_pci_get_auto_suspended(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return atomic_read(&pci_priv->auto_suspended);
+}
+
+static inline void cnss_pci_set_drv_connected(void *bus_priv, int val)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	atomic_set(&pci_priv->drv_connected, val);
+}
+
+static inline int cnss_pci_get_drv_connected(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return atomic_read(&pci_priv->drv_connected);
+}
+
+void cnss_mhi_controller_set_base(struct cnss_pci_data *pci_priv,
+				  phys_addr_t base);
+int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv);
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv);
+int cnss_pci_init(struct cnss_plat_data *plat_priv);
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
+void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv,
+				 char *prefix_name, char *name);
+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_tme_patch(struct cnss_pci_data *pci_priv);
+int cnss_pci_load_tme_opt_file(struct cnss_pci_data *pci_priv,
+				enum wlfw_tme_lite_file_type_v01 file);
+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_load_aux(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);
+#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv);
+#else
+static inline
+void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv);
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv);
+u32 cnss_pci_get_wake_msi(struct cnss_pci_data *pci_priv);
+int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_qmi_send_get(struct cnss_pci_data *pci_priv);
+int cnss_pci_qmi_send_put(struct cnss_pci_data *pci_priv);
+void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_powerup(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_crash_shutdown(struct cnss_pci_data *pci_priv);
+int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv);
+int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, void *data);
+int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv);
+int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv,
+				      int modem_current_status);
+void cnss_pci_pm_runtime_show_usage_count(struct cnss_pci_data *pci_priv);
+int cnss_pci_pm_request_resume(struct cnss_pci_data *pci_priv);
+int cnss_pci_pm_runtime_resume(struct cnss_pci_data *pci_priv);
+int cnss_pci_pm_runtime_get(struct cnss_pci_data *pci_priv,
+			    enum cnss_rtpm_id id);
+int cnss_pci_pm_runtime_get_sync(struct cnss_pci_data *pci_priv,
+				 enum cnss_rtpm_id id);
+void cnss_pci_pm_runtime_get_noresume(struct cnss_pci_data *pci_priv,
+				      enum cnss_rtpm_id id);
+int cnss_pci_pm_runtime_put_autosuspend(struct cnss_pci_data *pci_priv,
+					enum cnss_rtpm_id id);
+void cnss_pci_pm_runtime_put_noidle(struct cnss_pci_data *pci_priv,
+				    enum cnss_rtpm_id id);
+void cnss_pci_pm_runtime_mark_last_busy(struct cnss_pci_data *pci_priv);
+int cnss_pci_update_status(struct cnss_pci_data *pci_priv,
+			   enum cnss_driver_status status);
+int cnss_pci_call_driver_uevent(struct cnss_pci_data *pci_priv,
+				enum cnss_driver_status status, void *data);
+int cnss_pcie_is_device_down(struct cnss_pci_data *pci_priv);
+int cnss_pci_shutdown_cleanup(struct cnss_pci_data *pci_priv);
+int cnss_pci_suspend_bus(struct cnss_pci_data *pci_priv);
+int cnss_pci_resume_bus(struct cnss_pci_data *pci_priv);
+int cnss_pci_debug_reg_read(struct cnss_pci_data *pci_priv, u32 offset,
+			    u32 *val, bool raw_access);
+int cnss_pci_debug_reg_write(struct cnss_pci_data *pci_priv, u32 offset,
+			     u32 val, bool raw_access);
+int cnss_pci_get_iova(struct cnss_pci_data *pci_priv, u64 *addr, u64 *size);
+int cnss_pci_get_iova_ipa(struct cnss_pci_data *pci_priv, u64 *addr,
+			  u64 *size);
+bool cnss_pci_is_smmu_s1_enabled(struct cnss_pci_data *pci_priv);
+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);
+void cnss_register_iommu_fault_handler_irq(struct cnss_pci_data *pci_priv);
+#endif /* _CNSS_PCI_H */

+ 253 - 0
qcom/opensource/wlan/platform/cnss2/pci_platform.h

@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+#ifndef _CNSS_PCI_PLATFORM_H
+#define _CNSS_PCI_PLATFORM_H
+
+#include "pci.h"
+
+#if IS_ENABLED(CONFIG_PCI_MSM)
+/**
+ * _cnss_pci_enumerate() - Enumerate PCIe endpoints
+ * @plat_priv: driver platform context pointer
+ * @rc_num: root complex index that an endpoint connects to
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to power on root complex and enumerate the endpoint connected to it.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num);
+
+/**
+ * cnss_pci_assert_perst() - Assert PCIe PERST GPIO
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to assert PCIe PERST GPIO.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv);
+
+/**
+ * cnss_pci_disable_pc() - Disable PCIe link power collapse from RC driver
+ * @pci_priv: driver PCI bus context pointer
+ * @vote: value to indicate disable (true) or enable (false)
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to disable PCIe power collapse. The purpose of this API is to avoid
+ * root complex driver still controlling PCIe link from callbacks of
+ * system suspend/resume. Device driver itself should take full control
+ * of the link in such cases.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_pci_disable_pc(struct cnss_pci_data *pci_priv, bool vote);
+
+/**
+ * cnss_pci_set_link_bandwidth() - Update number of lanes and speed of
+ *                                 PCIe link
+ * @pci_priv: driver PCI bus context pointer
+ * @link_speed: PCIe link gen speed
+ * @link_width: number of lanes for PCIe link
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to update number of lanes and speed of the link.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv,
+				u16 link_speed, u16 link_width);
+
+/**
+ * cnss_pci_set_max_link_speed() - Set the maximum speed PCIe can link up with
+ * @pci_priv: driver PCI bus context pointer
+ * @rc_num: root complex index that an endpoint connects to
+ * @link_speed: PCIe link gen speed
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to update the maximum speed that PCIe can link up with.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_pci_set_max_link_speed(struct cnss_pci_data *pci_priv,
+				u32 rc_num, u16 link_speed);
+
+/**
+ * cnss_reg_pci_event() - Register for PCIe events
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to register for PCIe events like link down or WAKE GPIO toggling etc.
+ * The events should be based on PCIe root complex driver's capability.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_reg_pci_event(struct cnss_pci_data *pci_priv);
+void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv);
+
+/**
+ * cnss_wlan_adsp_pc_enable: Control ADSP power collapse setup
+ * @dev: Platform driver pci private data structure
+ * @control: Power collapse enable / disable
+ *
+ * This function controls ADSP power collapse (PC). It must be called
+ * based on wlan state.  ADSP power collapse during wlan RTPM suspend state
+ * results in delay during periodic QMI stats PCI link up/down. This delay
+ * causes additional power consumption.
+ *
+ * Result: 0 Success. negative error codes.
+ */
+int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv,
+			     bool control);
+int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up);
+int cnss_pci_prevent_l1(struct device *dev);
+void cnss_pci_allow_l1(struct device *dev);
+int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv);
+int cnss_pci_get_one_msi_assignment(struct cnss_pci_data *pci_priv);
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors);
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv);
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv);
+bool cnss_pci_is_force_one_msi(struct cnss_pci_data *pci_priv);
+int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv);
+void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv);
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable);
+/**
+ * _cnss_pci_get_reg_dump() - Dump PCIe RC registers for debug
+ * @pci_priv: driver PCI bus context pointer
+ * @buf: destination buffer pointer
+ * @len: length of the buffer
+ *
+ * This function shall call corresponding PCIe root complex driver API
+ * to dump PCIe RC registers for debug purpose.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int _cnss_pci_get_reg_dump(struct cnss_pci_data *pci_priv,
+			   u8 *buf, u32 len);
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable);
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv);
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv);
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed);
+#else
+int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_disable_pc(struct cnss_pci_data *pci_priv, bool vote)
+{
+	return 0;
+}
+
+int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv,
+				u16 link_speed, u16 link_width)
+{
+	return 0;
+}
+
+int cnss_pci_set_max_link_speed(struct cnss_pci_data *pci_priv,
+				u32 rc_num, u16 link_speed)
+{
+	return 0;
+}
+
+int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv) {}
+
+int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv, bool control)
+{
+	return 0;
+}
+
+int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
+{
+	return 0;
+}
+
+int cnss_pci_prevent_l1(struct device *dev)
+{
+	return 0;
+}
+EXPORT_SYMBOL(cnss_pci_prevent_l1);
+
+void cnss_pci_allow_l1(struct device *dev)
+{
+}
+EXPORT_SYMBOL(cnss_pci_allow_l1);
+
+int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+int _cnss_pci_get_reg_dump(struct cnss_pci_data *pci_priv,
+			   u8 *buf, u32 len)
+{
+	return 0;
+}
+
+void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->drv_supported = false;
+}
+
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_PCI_MSM */
+
+static inline bool cnss_pci_get_drv_supported(struct cnss_pci_data *pci_priv)
+{
+	return pci_priv->drv_supported;
+}
+
+#if IS_ENABLED(CONFIG_ARCH_QCOM)
+int cnss_pci_of_reserved_mem_device_init(struct cnss_pci_data *pci_priv);
+int cnss_pci_wake_gpio_init(struct cnss_pci_data *pci_priv);
+void cnss_pci_wake_gpio_deinit(struct cnss_pci_data *pci_priv);
+#endif /* CONFIG_ARCH_QCOM */
+#endif /* _CNSS_PCI_PLATFORM_H*/

+ 829 - 0
qcom/opensource/wlan/platform/cnss2/pci_qcom.c

@@ -0,0 +1,829 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+#include "pci_platform.h"
+#include "debug.h"
+
+static struct cnss_msi_config msi_config = {
+	.total_vectors = 32,
+	.total_users = MSI_USERS,
+	.users = (struct cnss_msi_user[]) {
+		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
+		{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
+		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
+		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
+	},
+};
+
+#ifdef CONFIG_ONE_MSI_VECTOR
+/**
+ * All the user share the same vector and msi data
+ * For MHI user, we need pass IRQ array information to MHI component
+ * MHI_IRQ_NUMBER is defined to specify this MHI IRQ array size
+ */
+#define MHI_IRQ_NUMBER 3
+static struct cnss_msi_config msi_config_one_msi = {
+	.total_vectors = 1,
+	.total_users = 4,
+	.users = (struct cnss_msi_user[]) {
+		{ .name = "MHI", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
+		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
+	},
+};
+#endif
+
+#define ENUM_RETRY_MAX_TIMES 8
+#define ENUM_RETRY_DELAY_MS 500
+
+int _cnss_pci_enumerate(struct cnss_plat_data *plat_priv, u32 rc_num)
+{
+	u32 retry = 0;
+	int ret;
+
+	if (plat_priv->pcie_switch_type == PCIE_SWITCH_NTN3) {
+		while (retry++ < ENUM_RETRY_MAX_TIMES) {
+			ret = msm_pcie_enumerate(rc_num);
+			/* For PCIe switch platform, cnss_probe may called
+			 * before PCIe switch hardware ready, wait for
+			 * msm_pcie_enumerate complete.
+			 */
+			if (ret == -EPROBE_DEFER) {
+				cnss_pr_dbg("PCIe RC%d not ready, retry:%dth\n",
+					    rc_num, retry);
+				msleep(ENUM_RETRY_DELAY_MS);
+			}
+		}
+	} else {
+		return msm_pcie_enumerate(rc_num);
+	}
+
+	return ret;
+}
+
+int cnss_pci_assert_perst(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	return msm_pcie_pm_control(MSM_PCIE_HANDLE_LINKDOWN,
+				   pci_dev->bus->number, pci_dev, NULL,
+				   PM_OPTIONS_DEFAULT);
+}
+
+int cnss_pci_disable_pc(struct cnss_pci_data *pci_priv, bool vote)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	return msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC :
+				   MSM_PCIE_ENABLE_PC,
+				   pci_dev->bus->number, pci_dev, NULL,
+				   PM_OPTIONS_DEFAULT);
+}
+
+int cnss_pci_set_link_bandwidth(struct cnss_pci_data *pci_priv,
+				u16 link_speed, u16 link_width)
+{
+	return msm_pcie_set_link_bandwidth(pci_priv->pci_dev,
+					   link_speed, link_width);
+}
+
+int cnss_pci_set_max_link_speed(struct cnss_pci_data *pci_priv,
+				u32 rc_num, u16 link_speed)
+{
+	return msm_pcie_set_target_link_speed(rc_num, link_speed, false);
+}
+
+/**
+ * _cnss_pci_prevent_l1() - Prevent PCIe L1 and L1 sub-states
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to prevent PCIe link enter L1 and L1 sub-states. The APIs should also
+ * bring link out of L1 or L1 sub-states if any and avoid synchronization
+ * issues if any.
+ *
+ * Return: 0 for success, negative value for error
+ */
+static int _cnss_pci_prevent_l1(struct cnss_pci_data *pci_priv)
+{
+	return msm_pcie_prevent_l1(pci_priv->pci_dev);
+}
+
+/**
+ * _cnss_pci_allow_l1() - Allow PCIe L1 and L1 sub-states
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to allow PCIe link enter L1 and L1 sub-states. The APIs should avoid
+ * synchronization issues if any.
+ *
+ * Return: 0 for success, negative value for error
+ */
+static void _cnss_pci_allow_l1(struct cnss_pci_data *pci_priv)
+{
+	msm_pcie_allow_l1(pci_priv->pci_dev);
+}
+
+/**
+ * cnss_pci_set_link_up() - Power on or resume PCIe link
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to Power on or resume PCIe link.
+ *
+ * Return: 0 for success, negative value for error
+ */
+static int cnss_pci_set_link_up(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	enum msm_pcie_pm_opt pm_ops = MSM_PCIE_RESUME;
+	u32 pm_options = PM_OPTIONS_DEFAULT;
+	int ret;
+
+	ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev,
+				  NULL, pm_options);
+	if (ret)
+		cnss_pr_err("Failed to resume PCI link with default option, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+/**
+ * cnss_pci_set_link_down() - Power off or suspend PCIe link
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding PCIe root complex driver APIs
+ * to power off or suspend PCIe link.
+ *
+ * Return: 0 for success, negative value for error
+ */
+static int cnss_pci_set_link_down(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	enum msm_pcie_pm_opt pm_ops;
+	u32 pm_options = PM_OPTIONS_DEFAULT;
+	int ret;
+
+	if (pci_priv->drv_connected_last) {
+		cnss_pr_vdbg("Use PCIe DRV suspend\n");
+		pm_ops = MSM_PCIE_DRV_SUSPEND;
+	} else {
+		if (plat_priv && PCIE_SWITCH_NTN3 == plat_priv->pcie_switch_type) {
+			cnss_pr_dbg("Skip suspend from client side for pcie switch case\n");
+			return 0;
+		}
+		pm_ops = MSM_PCIE_SUSPEND;
+	}
+
+	ret = msm_pcie_pm_control(pm_ops, pci_dev->bus->number, pci_dev,
+				  NULL, pm_options);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link with default option, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+void cnss_pci_update_drv_supported(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *root_port = pcie_find_root_port(pci_priv->pci_dev);
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device_node *root_of_node;
+	bool drv_supported = false;
+
+	if (!root_port) {
+		cnss_pr_err("PCIe DRV is not supported as root port is null\n");
+		pci_priv->drv_supported = false;
+		return;
+	}
+
+	root_of_node = root_port->dev.of_node;
+
+	if (root_of_node->parent) {
+		drv_supported = of_property_read_bool(root_of_node->parent,
+						      "qcom,drv-supported") ||
+				of_property_read_bool(root_of_node->parent,
+						      "qcom,drv-name");
+	}
+
+	cnss_pr_dbg("PCIe DRV is %s\n",
+		    drv_supported ? "supported" : "not supported");
+	pci_priv->drv_supported = drv_supported;
+
+	if (drv_supported) {
+		plat_priv->cap.cap_flag |= CNSS_HAS_DRV_SUPPORT;
+		cnss_set_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01);
+	}
+}
+
+static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
+{
+	struct pci_dev *pci_dev;
+	struct cnss_pci_data *pci_priv;
+	struct device *dev;
+	struct cnss_plat_data *plat_priv = NULL;
+	int ret = 0;
+
+	if (!notify)
+		return;
+
+	pci_dev = notify->user;
+	if (!pci_dev)
+		return;
+
+	pci_priv = cnss_get_pci_priv(pci_dev);
+	if (!pci_priv)
+		return;
+	dev = &pci_priv->pci_dev->dev;
+
+	switch (notify->event) {
+	case MSM_PCIE_EVENT_LINK_RECOVER:
+		cnss_pr_dbg("PCI link recover callback\n");
+
+		plat_priv = pci_priv->plat_priv;
+		if (!plat_priv) {
+			cnss_pr_err("plat_priv is NULL\n");
+			return;
+		}
+
+		plat_priv->ctrl_params.quirks |= BIT(LINK_DOWN_SELF_RECOVERY);
+
+		ret = msm_pcie_pm_control(MSM_PCIE_HANDLE_LINKDOWN,
+					  pci_dev->bus->number, pci_dev, NULL,
+					  PM_OPTIONS_DEFAULT);
+		if (ret)
+			cnss_pci_handle_linkdown(pci_priv);
+		break;
+	case MSM_PCIE_EVENT_LINKDOWN:
+		cnss_pr_dbg("PCI link down event callback\n");
+		cnss_pci_handle_linkdown(pci_priv);
+		break;
+	case MSM_PCIE_EVENT_WAKEUP:
+		cnss_pr_dbg("PCI Wake up event callback\n");
+		if ((cnss_pci_get_monitor_wake_intr(pci_priv) &&
+		     cnss_pci_get_auto_suspended(pci_priv)) ||
+		     dev->power.runtime_status == RPM_SUSPENDING) {
+			cnss_pci_set_monitor_wake_intr(pci_priv, false);
+			cnss_pci_pm_request_resume(pci_priv);
+		}
+		complete(&pci_priv->wake_event_complete);
+		break;
+	case MSM_PCIE_EVENT_DRV_CONNECT:
+		cnss_pr_dbg("DRV subsystem is connected\n");
+		cnss_pci_set_drv_connected(pci_priv, 1);
+		break;
+	case MSM_PCIE_EVENT_DRV_DISCONNECT:
+		cnss_pr_dbg("DRV subsystem is disconnected\n");
+		if (cnss_pci_get_auto_suspended(pci_priv))
+			cnss_pci_pm_request_resume(pci_priv);
+		cnss_pci_set_drv_connected(pci_priv, 0);
+		break;
+	default:
+		cnss_pr_err("Received invalid PCI event: %d\n", notify->event);
+	}
+}
+
+int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct msm_pcie_register_event *pci_event;
+
+	pci_event = &pci_priv->msm_pci_event;
+	pci_event->events = MSM_PCIE_EVENT_LINK_RECOVER |
+			    MSM_PCIE_EVENT_LINKDOWN |
+			    MSM_PCIE_EVENT_WAKEUP;
+
+	if (cnss_pci_get_drv_supported(pci_priv))
+		pci_event->events = pci_event->events |
+			MSM_PCIE_EVENT_DRV_CONNECT |
+			MSM_PCIE_EVENT_DRV_DISCONNECT;
+
+	pci_event->user = pci_priv->pci_dev;
+	pci_event->mode = MSM_PCIE_TRIGGER_CALLBACK;
+	pci_event->callback = cnss_pci_event_cb;
+	pci_event->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+	ret = msm_pcie_register_event(pci_event);
+	if (ret)
+		cnss_pr_err("Failed to register MSM PCI event, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv)
+{
+	msm_pcie_deregister_event(&pci_priv->msm_pci_event);
+}
+
+int cnss_wlan_adsp_pc_enable(struct cnss_pci_data *pci_priv,
+			     bool control)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	int ret = 0;
+	u32 pm_options = PM_OPTIONS_DEFAULT;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	if (!cnss_pci_get_drv_supported(pci_priv))
+		return 0;
+
+	if (plat_priv->adsp_pc_enabled == control) {
+		cnss_pr_dbg("ADSP power collapse already %s\n",
+			    control ? "Enabled" : "Disabled");
+		return 0;
+	}
+
+	if (control)
+		pm_options &= ~MSM_PCIE_CONFIG_NO_DRV_PC;
+	else
+		pm_options |= MSM_PCIE_CONFIG_NO_DRV_PC;
+
+	ret = msm_pcie_pm_control(MSM_PCIE_DRV_PC_CTRL, pci_dev->bus->number,
+				  pci_dev, NULL, pm_options);
+	if (ret)
+		return ret;
+
+	cnss_pr_dbg("%s ADSP power collapse\n", control ? "Enable" : "Disable");
+	plat_priv->adsp_pc_enabled = control;
+	return 0;
+}
+
+static int cnss_set_pci_link_status(struct cnss_pci_data *pci_priv,
+				    enum pci_link_status status)
+{
+	u16 link_speed, link_width = pci_priv->def_link_width;
+	u16 one_lane = PCI_EXP_LNKSTA_NLW_X1 >> PCI_EXP_LNKSTA_NLW_SHIFT;
+	int ret;
+
+	cnss_pr_vdbg("Set PCI link status to: %u\n", status);
+
+	switch (status) {
+	case PCI_GEN1:
+		link_speed = PCI_EXP_LNKSTA_CLS_2_5GB;
+		if (!link_width)
+			link_width = one_lane;
+		break;
+	case PCI_GEN2:
+		link_speed = PCI_EXP_LNKSTA_CLS_5_0GB;
+		if (!link_width)
+			link_width = one_lane;
+		break;
+	case PCI_DEF:
+		link_speed = pci_priv->def_link_speed;
+		if (!link_speed || !link_width) {
+			cnss_pr_err("PCI link speed or width is not valid\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		cnss_pr_err("Unknown PCI link status config: %u\n", status);
+		return -EINVAL;
+	}
+
+	ret = cnss_pci_set_link_bandwidth(pci_priv, link_speed, link_width);
+	if (!ret)
+		pci_priv->cur_link_speed = link_speed;
+
+	return ret;
+}
+
+int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
+{
+	int ret = 0, retry = 0;
+	struct cnss_plat_data *plat_priv;
+	int sw_ctrl_gpio;
+
+	plat_priv = pci_priv->plat_priv;
+	sw_ctrl_gpio = plat_priv->pinctrl_info.sw_ctrl_gpio;
+
+	cnss_pr_vdbg("%s PCI link\n", link_up ? "Resuming" : "Suspending");
+
+	if (link_up) {
+retry:
+		ret = cnss_pci_set_link_up(pci_priv);
+		if (ret && retry++ < LINK_TRAINING_RETRY_MAX_TIMES) {
+			cnss_pr_dbg("Retry PCI link training #%d\n", retry);
+			cnss_pr_dbg("Value of SW_CTRL GPIO: %d\n",
+				    cnss_get_input_gpio_value(plat_priv, sw_ctrl_gpio));
+			if (pci_priv->pci_link_down_ind)
+				msleep(LINK_TRAINING_RETRY_DELAY_MS * retry);
+			goto retry;
+		}
+	} else {
+		/* Since DRV suspend cannot be done in Gen 3, set it to
+		 * Gen 2 if current link speed is larger than Gen 2.
+		 */
+		if (pci_priv->drv_connected_last &&
+		    pci_priv->cur_link_speed > PCI_EXP_LNKSTA_CLS_5_0GB)
+			cnss_set_pci_link_status(pci_priv, PCI_GEN2);
+
+		ret = cnss_pci_set_link_down(pci_priv);
+	}
+
+	if (pci_priv->drv_connected_last) {
+		if ((link_up && !ret) || (!link_up && ret))
+			cnss_set_pci_link_status(pci_priv, PCI_DEF);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PCIE_SWITCH_SUPPORT
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_priv->pci_dsp_link_status = link_enable;
+	return msm_pcie_dsp_link_control(pci_priv->pci_dev, link_enable);
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_priv->pci_dsp_link_status = link_enable;
+
+	return 0;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	return pci_priv->pci_dsp_link_status;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	int retry_count = 0;
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	plat_priv = pci_priv->plat_priv;
+	/* For PCIe switch platform, wait for link train of DSP<->WLAN complete
+	 */
+	while (retry_count++ < DSP_LINK_ENABLE_RETRY_COUNT_MAX) {
+		ret = cnss_pci_dsp_link_control(pci_priv, true);
+		if (!ret)
+			break;
+
+		cnss_pci_dsp_link_control(pci_priv, false);
+		cnss_pr_err("DSP<->WLAN link train failed, retry...\n");
+		cnss_select_pinctrl_state(plat_priv, false);
+		usleep_range(DSP_LINK_ENABLE_DELAY_TIME_US_MIN,
+			     DSP_LINK_ENABLE_DELAY_TIME_US_MAX);
+		ret = cnss_select_pinctrl_enable(plat_priv);
+		if (ret) {
+			cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret);
+			return ret;
+		}
+		usleep_range(DSP_LINK_ENABLE_DELAY_TIME_US_MIN,
+			     DSP_LINK_ENABLE_DELAY_TIME_US_MAX);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PCIE_SWITCH_RETRAIN_LINK_SUPPORT
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Setting DSP <-> EP link speed:0x%x\n", target_link_speed);
+
+	ret = msm_pcie_retrain_port_link(pci_priv->pci_dev, target_link_speed);
+	if (ret) {
+		cnss_pr_err("Failed to retrain link, err = %d\n", ret);
+		return ret;
+	}
+
+	pci_priv->def_link_speed = target_link_speed;
+
+	return ret;
+}
+#else
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+#else
+int cnss_pci_dsp_link_control(struct cnss_pci_data *pci_priv,
+			      bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_set_dsp_link_status(struct cnss_pci_data *pci_priv,
+				 bool link_enable)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_get_dsp_link_status(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_enable(struct cnss_pci_data *pci_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+int cnss_pci_dsp_link_retrain(struct cnss_pci_data *pci_priv,
+			      u16 target_link_speed)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+int cnss_pci_prevent_l1(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	int ret;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
+		cnss_pr_dbg("PCIe link is in suspend state\n");
+		return -EIO;
+	}
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_err("PCIe link is down\n");
+		return -EIO;
+	}
+
+	ret = _cnss_pci_prevent_l1(pci_priv);
+	if (ret == -EIO) {
+		cnss_pr_err("Failed to prevent PCIe L1, considered as link down\n");
+		cnss_pci_link_down(dev);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_pci_prevent_l1);
+
+void cnss_pci_allow_l1(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return;
+	}
+
+	if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
+		cnss_pr_dbg("PCIe link is in suspend state\n");
+		return;
+	}
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_err("PCIe link is down\n");
+		return;
+	}
+
+	_cnss_pci_allow_l1(pci_priv);
+}
+EXPORT_SYMBOL(cnss_pci_allow_l1);
+
+int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->msi_config = &msi_config;
+
+	return 0;
+}
+
+#ifdef CONFIG_ONE_MSI_VECTOR
+int cnss_pci_get_one_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->msi_config = &msi_config_one_msi;
+
+	return 0;
+}
+
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_msi_config *msi_config;
+
+	cnss_pci_get_one_msi_assignment(pci_priv);
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("one msi_config is NULL!\n");
+		return false;
+	}
+	*num_vectors = pci_alloc_irq_vectors(pci_dev,
+					     msi_config->total_vectors,
+					     msi_config->total_vectors,
+					     PCI_IRQ_MSI);
+	if (*num_vectors < 0) {
+		cnss_pr_err("Failed to get one MSI vector!\n");
+		return false;
+	}
+	cnss_pr_dbg("request MSI one vector\n");
+
+	return true;
+}
+
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv)
+{
+	return pci_priv && pci_priv->msi_config &&
+	       (pci_priv->msi_config->total_vectors == 1);
+}
+
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv)
+{
+	return MHI_IRQ_NUMBER;
+}
+
+bool cnss_pci_is_force_one_msi(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	return test_bit(FORCE_ONE_MSI, &plat_priv->ctrl_params.quirks);
+}
+#else
+int cnss_pci_get_one_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+bool cnss_pci_fallback_one_msi(struct cnss_pci_data *pci_priv,
+			       int *num_vectors)
+{
+	return false;
+}
+
+bool cnss_pci_is_one_msi(struct cnss_pci_data *pci_priv)
+{
+	return false;
+}
+
+int cnss_pci_get_one_msi_mhi_irq_array_size(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+bool cnss_pci_is_force_one_msi(struct cnss_pci_data *pci_priv)
+{
+	return false;
+}
+#endif
+
+static int cnss_pci_smmu_fault_handler(struct iommu_domain *domain,
+				       struct device *dev, unsigned long iova,
+				       int flags, void *handler_token)
+{
+	struct cnss_pci_data *pci_priv = handler_token;
+
+	cnss_fatal_err("SMMU fault happened with IOVA 0x%lx\n", iova);
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	pci_priv->is_smmu_fault = true;
+	cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
+	cnss_force_fw_assert(&pci_priv->pci_dev->dev);
+
+	/* IOMMU driver requires -ENOSYS to print debug info. */
+	return -ENOSYS;
+}
+
+int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct device_node *of_node;
+	struct resource *res;
+	const char *iommu_dma_type;
+	u32 addr_win[2];
+	int ret = 0;
+
+	of_node = of_parse_phandle(pci_dev->dev.of_node, "qcom,iommu-group", 0);
+	if (!of_node)
+		return ret;
+
+	cnss_pr_dbg("Initializing SMMU\n");
+
+	pci_priv->iommu_domain = iommu_get_domain_for_dev(&pci_dev->dev);
+	ret = of_property_read_string(of_node, "qcom,iommu-dma",
+				      &iommu_dma_type);
+	if (!ret && !strcmp("fastmap", iommu_dma_type)) {
+		cnss_pr_dbg("Enabling SMMU S1 stage\n");
+		pci_priv->smmu_s1_enable = true;
+		iommu_set_fault_handler(pci_priv->iommu_domain,
+					cnss_pci_smmu_fault_handler, pci_priv);
+		cnss_register_iommu_fault_handler_irq(pci_priv);
+	}
+
+	ret = of_property_read_u32_array(of_node,  "qcom,iommu-dma-addr-pool",
+					 addr_win, ARRAY_SIZE(addr_win));
+	if (ret) {
+		cnss_pr_err("Invalid SMMU size window, err = %d\n", ret);
+		of_node_put(of_node);
+		return ret;
+	}
+
+	pci_priv->smmu_iova_start = addr_win[0];
+	pci_priv->smmu_iova_len = addr_win[1];
+	cnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: 0x%zx\n",
+		    &pci_priv->smmu_iova_start,
+		    pci_priv->smmu_iova_len);
+
+	res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM,
+					   "smmu_iova_ipa");
+	if (res) {
+		pci_priv->smmu_iova_ipa_start = res->start;
+		pci_priv->smmu_iova_ipa_current = res->start;
+		pci_priv->smmu_iova_ipa_len = resource_size(res);
+		cnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: 0x%zx\n",
+			    &pci_priv->smmu_iova_ipa_start,
+			    pci_priv->smmu_iova_ipa_len);
+	}
+
+	pci_priv->iommu_geometry = of_property_read_bool(of_node,
+							 "qcom,iommu-geometry");
+	cnss_pr_dbg("iommu_geometry: %d\n", pci_priv->iommu_geometry);
+
+	of_node_put(of_node);
+
+	return 0;
+}
+
+int _cnss_pci_get_reg_dump(struct cnss_pci_data *pci_priv,
+			   u8 *buf, u32 len)
+{
+	return msm_pcie_reg_dump(pci_priv->pci_dev, buf, len);
+}
+
+#if IS_ENABLED(CONFIG_ARCH_QCOM)
+/**
+ * cnss_pci_of_reserved_mem_device_init() - Assign reserved memory region
+ *                                          to given PCI device
+ * @pci_priv: driver PCI bus context pointer
+ *
+ * This function shall call corresponding of_reserved_mem_device* API to
+ * assign reserved memory region to PCI device based on where the memory is
+ * defined and attached to (platform device of_node or PCI device of_node)
+ * in device tree.
+ *
+ * Return: 0 for success, negative value for error
+ */
+int cnss_pci_of_reserved_mem_device_init(struct cnss_pci_data *pci_priv)
+{
+	struct device *dev_pci = &pci_priv->pci_dev->dev;
+	int ret;
+
+	/* Use of_reserved_mem_device_init_by_idx() if reserved memory is
+	 * attached to platform device of_node.
+	 */
+	ret = of_reserved_mem_device_init(dev_pci);
+	if (ret) {
+		if (ret == -EINVAL)
+			cnss_pr_vdbg("Ignore, no specific reserved-memory assigned\n");
+		else
+			cnss_pr_err("Failed to init reserved mem device, err = %d\n",
+				    ret);
+	}
+	if (dev_pci->cma_area)
+		cnss_pr_dbg("CMA area is %s\n",
+			    cma_get_name(dev_pci->cma_area));
+
+	return ret;
+}
+
+int cnss_pci_wake_gpio_init(struct cnss_pci_data *pci_priv)
+{
+	return 0;
+}
+
+void cnss_pci_wake_gpio_deinit(struct cnss_pci_data *pci_priv)
+{
+}
+#endif
+

+ 12 - 0
qcom/opensource/wlan/platform/cnss2/pineapple_consolidate_defconfig

@@ -0,0 +1,12 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS2_DEBUG=y

+ 11 - 0
qcom/opensource/wlan/platform/cnss2/pineapple_gki_defconfig

@@ -0,0 +1,11 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 2065 - 0
qcom/opensource/wlan/platform/cnss2/power.c

@@ -0,0 +1,2065 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/qcom-pinctrl.h>
+#include <linux/regulator/consumer.h>
+#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
+#include <soc/qcom/cmd-db.h>
+#endif
+
+#include "main.h"
+#include "debug.h"
+#include "bus.h"
+#include <linux/soc/qcom/qcom_aoss.h>
+#include "pci_platform.h"
+
+#if IS_ENABLED(CONFIG_ARCH_QCOM)
+static struct cnss_vreg_cfg cnss_vreg_list[] = {
+	{"vdd-wlan-m2", 3300000, 3300000, 0, 0, 0},
+	{"vdd-wlan-core", 1300000, 1300000, 0, 0, 0},
+	{"vdd-wlan-io", 1800000, 1800000, 0, 0, 0},
+	{"vdd-wlan-io12", 1200000, 1200000, 0, 0, 0},
+	{"vdd-wlan-ant-share", 1800000, 1800000, 0, 0, 0},
+	{"vdd-wlan-xtal-aon", 0, 0, 0, 0, 0},
+	{"vdd-wlan-xtal", 1800000, 1800000, 0, 2, 0},
+	{"vdd-wlan", 0, 0, 0, 0, 0},
+	{"vdd-wlan-ctrl1", 0, 0, 0, 0, 0},
+	{"vdd-wlan-ctrl2", 0, 0, 0, 0, 0},
+	{"vdd-wlan-sp2t", 2700000, 2700000, 0, 0, 0},
+	{"wlan-ant-switch", 1800000, 1800000, 0, 0, 0},
+	{"wlan-soc-swreg", 1200000, 1200000, 0, 0, 0},
+	{"vdd-wlan-aon", 950000, 950000, 0, 0, 0},
+	{"vdd-wlan-dig", 950000, 952000, 0, 0, 0},
+	{"vdd-wlan-rfa1", 1900000, 1900000, 0, 0, 0},
+	{"vdd-wlan-rfa2", 1350000, 1350000, 0, 0, 0},
+	{"vdd-wlan-rfa3", 1900000, 1900000, 450000, 0, 0},
+	{"alt-sleep-clk", 0, 0, 0, 0, 0},
+	{"vdd-wlan-en", 0, 0, 0, 10, 0},
+};
+
+static struct cnss_clk_cfg cnss_clk_list[] = {
+	{"rf_clk", 0, 0},
+};
+#else
+static struct cnss_vreg_cfg cnss_vreg_list[] = {
+};
+
+static struct cnss_clk_cfg cnss_clk_list[] = {
+};
+#endif
+
+#define CNSS_VREG_INFO_SIZE		ARRAY_SIZE(cnss_vreg_list)
+#define CNSS_CLK_INFO_SIZE		ARRAY_SIZE(cnss_clk_list)
+#define MAX_PROP_SIZE			32
+
+#define BOOTSTRAP_GPIO			"qcom,enable-bootstrap-gpio"
+#define BOOTSTRAP_ACTIVE		"bootstrap_active"
+#define HOST_SOL_GPIO			"wlan-host-sol-gpio"
+#define DEV_SOL_GPIO			"wlan-dev-sol-gpio"
+#define SOL_DEFAULT			"sol_default"
+#define WLAN_EN_GPIO			"wlan-en-gpio"
+#define BT_EN_GPIO			"qcom,bt-en-gpio"
+#define XO_CLK_GPIO			"qcom,xo-clk-gpio"
+#define SW_CTRL_GPIO			"qcom,sw-ctrl-gpio"
+#define WLAN_SW_CTRL_GPIO		"qcom,wlan-sw-ctrl-gpio"
+#define WLAN_EN_ACTIVE			"wlan_en_active"
+#define WLAN_EN_SLEEP			"wlan_en_sleep"
+#define WLAN_VREGS_PROP			"wlan_vregs"
+
+/* unit us */
+#define BOOTSTRAP_DELAY			1000
+#define WLAN_ENABLE_DELAY		1000
+/* unit ms */
+#define WLAN_ENABLE_DELAY_ROME		10
+
+#define TCS_CMD_DATA_ADDR_OFFSET	0x4
+#define TCS_OFFSET			0xC8
+#define TCS_CMD_OFFSET			0x10
+#define MAX_TCS_NUM			8
+#define MAX_TCS_CMD_NUM			5
+#define BT_CXMX_VOLTAGE_MV		950
+#define CNSS_MBOX_MSG_MAX_LEN 64
+#define CNSS_MBOX_TIMEOUT_MS 1000
+/* Platform HW config */
+#define CNSS_PMIC_VOLTAGE_STEP 4
+#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
+ * @CNSS_VREG_VOLTAGE: Provides voltage level in mV to be configured in TCS
+ * @CNSS_VREG_MODE: Regulator mode
+ * @CNSS_VREG_TCS_ENABLE: Set bool Voltage regulator enable config in TCS.
+ */
+enum cnss_aop_vreg_param {
+	CNSS_VREG_VOLTAGE,
+	CNSS_VREG_MODE,
+	CNSS_VREG_ENABLE,
+	CNSS_VREG_PARAM_MAX
+};
+
+/** enum cnss_aop_vreg_param_mode: Voltage modes supported by AOP*/
+enum cnss_aop_vreg_param_mode {
+	CNSS_VREG_RET_MODE = 3,
+	CNSS_VREG_LPM_MODE = 4,
+	CNSS_VREG_AUTO_MODE = 6,
+	CNSS_VREG_NPM_MODE = 7,
+	CNSS_VREG_MODE_MAX
+};
+
+/**
+ * enum cnss_aop_tcs_seq: TCS sequence ID for trigger
+ * @CNSS_TCS_UP_SEQ: TCS Sequence based on up trigger / Wake TCS
+ * @CNSS_TCS_DOWN_SEQ: TCS Sequence based on down trigger / Sleep TCS
+ * @CNSS_TCS_ENABLE_SEQ: Enable this TCS seq entry
+ */
+enum cnss_aop_tcs_seq_param {
+	CNSS_TCS_UP_SEQ,
+	CNSS_TCS_DOWN_SEQ,
+	CNSS_TCS_ENABLE_SEQ,
+	CNSS_TCS_SEQ_MAX
+};
+
+static int cnss_get_vreg_single(struct cnss_plat_data *plat_priv,
+				struct cnss_vreg_info *vreg)
+{
+	int ret = 0;
+	struct device *dev;
+	struct regulator *reg;
+	const __be32 *prop;
+	char prop_name[MAX_PROP_SIZE] = {0};
+	int len;
+	struct device_node *dt_node;
+
+	dev = &plat_priv->plat_dev->dev;
+	dt_node = (plat_priv->dev_node ? plat_priv->dev_node : dev->of_node);
+
+	reg = devm_regulator_get_optional(dev, vreg->cfg.name);
+	if (IS_ERR(reg)) {
+		ret = PTR_ERR(reg);
+		if (ret == -ENODEV)
+			return ret;
+		else if (ret == -EPROBE_DEFER)
+			cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
+				     vreg->cfg.name);
+		else
+			cnss_pr_err("Failed to get regulator %s, err = %d\n",
+				    vreg->cfg.name, ret);
+		return ret;
+	}
+
+	vreg->reg = reg;
+
+	snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-config",
+		 vreg->cfg.name);
+
+	prop = of_get_property(dt_node, prop_name, &len);
+	if (!prop || len != (5 * sizeof(__be32))) {
+		cnss_pr_dbg("Property %s %s, use default\n", prop_name,
+			    prop ? "invalid format" : "doesn't exist");
+	} else {
+		vreg->cfg.min_uv = be32_to_cpup(&prop[0]);
+		vreg->cfg.max_uv = be32_to_cpup(&prop[1]);
+		vreg->cfg.load_ua = be32_to_cpup(&prop[2]);
+		vreg->cfg.delay_us = be32_to_cpup(&prop[3]);
+		vreg->cfg.need_unvote = be32_to_cpup(&prop[4]);
+	}
+
+	cnss_pr_dbg("Got regulator: %s, min_uv: %u, max_uv: %u, load_ua: %u, delay_us: %u, need_unvote: %u\n",
+		    vreg->cfg.name, vreg->cfg.min_uv,
+		    vreg->cfg.max_uv, vreg->cfg.load_ua,
+		    vreg->cfg.delay_us, vreg->cfg.need_unvote);
+
+	return 0;
+}
+
+static void cnss_put_vreg_single(struct cnss_plat_data *plat_priv,
+				 struct cnss_vreg_info *vreg)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+
+	cnss_pr_dbg("Put regulator: %s\n", vreg->cfg.name);
+	devm_regulator_put(vreg->reg);
+	devm_kfree(dev, vreg);
+}
+
+static int cnss_vreg_on_single(struct cnss_vreg_info *vreg)
+{
+	int ret = 0;
+
+	if (vreg->enabled) {
+		cnss_pr_dbg("Regulator %s is already enabled\n",
+			    vreg->cfg.name);
+		return 0;
+	}
+
+	cnss_pr_dbg("Regulator %s is being enabled\n", vreg->cfg.name);
+
+	if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
+		ret = regulator_set_voltage(vreg->reg,
+					    vreg->cfg.min_uv,
+					    vreg->cfg.max_uv);
+
+		if (ret) {
+			cnss_pr_err("Failed to set voltage for regulator %s, min_uv: %u, max_uv: %u, err = %d\n",
+				    vreg->cfg.name, vreg->cfg.min_uv,
+				    vreg->cfg.max_uv, ret);
+			goto out;
+		}
+	}
+
+	if (vreg->cfg.load_ua) {
+		ret = regulator_set_load(vreg->reg,
+					 vreg->cfg.load_ua);
+
+		if (ret < 0) {
+			cnss_pr_err("Failed to set load for regulator %s, load: %u, err = %d\n",
+				    vreg->cfg.name, vreg->cfg.load_ua,
+				    ret);
+			goto out;
+		}
+	}
+
+	if (vreg->cfg.delay_us)
+		udelay(vreg->cfg.delay_us);
+
+	ret = regulator_enable(vreg->reg);
+	if (ret) {
+		cnss_pr_err("Failed to enable regulator %s, err = %d\n",
+			    vreg->cfg.name, ret);
+		goto out;
+	}
+	vreg->enabled = true;
+
+out:
+	return ret;
+}
+
+static int cnss_vreg_unvote_single(struct cnss_vreg_info *vreg)
+{
+	int ret = 0;
+
+	if (!vreg->enabled) {
+		cnss_pr_dbg("Regulator %s is already disabled\n",
+			    vreg->cfg.name);
+		return 0;
+	}
+
+	cnss_pr_dbg("Removing vote for Regulator %s\n", vreg->cfg.name);
+
+	if (vreg->cfg.load_ua) {
+		ret = regulator_set_load(vreg->reg, 0);
+		if (ret < 0)
+			cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
+				    vreg->cfg.name, ret);
+	}
+
+	if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
+		ret = regulator_set_voltage(vreg->reg, 0,
+					    vreg->cfg.max_uv);
+		if (ret)
+			cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
+				    vreg->cfg.name, ret);
+	}
+
+	return ret;
+}
+
+static int cnss_vreg_off_single(struct cnss_vreg_info *vreg)
+{
+	int ret = 0;
+
+	if (!vreg->enabled) {
+		cnss_pr_dbg("Regulator %s is already disabled\n",
+			    vreg->cfg.name);
+		return 0;
+	}
+
+	cnss_pr_dbg("Regulator %s is being disabled\n",
+		    vreg->cfg.name);
+
+	ret = regulator_disable(vreg->reg);
+	if (ret)
+		cnss_pr_err("Failed to disable regulator %s, err = %d\n",
+			    vreg->cfg.name, ret);
+
+	if (vreg->cfg.load_ua) {
+		ret = regulator_set_load(vreg->reg, 0);
+		if (ret < 0)
+			cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
+				    vreg->cfg.name, ret);
+	}
+
+	if (vreg->cfg.min_uv != 0 && vreg->cfg.max_uv != 0) {
+		ret = regulator_set_voltage(vreg->reg, 0,
+					    vreg->cfg.max_uv);
+		if (ret)
+			cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
+				    vreg->cfg.name, ret);
+	}
+	vreg->enabled = false;
+
+	return ret;
+}
+
+static struct cnss_vreg_cfg *get_vreg_list(u32 *vreg_list_size,
+					   enum cnss_vreg_type type)
+{
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		*vreg_list_size = CNSS_VREG_INFO_SIZE;
+		return cnss_vreg_list;
+	default:
+		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
+		*vreg_list_size = 0;
+		return NULL;
+	}
+}
+
+/*
+ * For multi-exchg dt node, get the required vregs' names from property
+ * 'wlan_vregs', which is string array;
+ *
+ * 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'.
+ */
+static int cnss_get_vreg(struct cnss_plat_data *plat_priv,
+			 struct list_head *vreg_list,
+			 struct cnss_vreg_cfg *vreg_cfg,
+			 u32 vreg_list_size)
+{
+	int ret = 0;
+	int i;
+	struct cnss_vreg_info *vreg;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	int id_n;
+	struct device_node *dt_node;
+
+	if (!list_empty(vreg_list) &&
+	    (plat_priv->dt_type != CNSS_DTT_MULTIEXCHG)) {
+		cnss_pr_dbg("Vregs have already been updated\n");
+		return 0;
+	}
+
+	dt_node = (plat_priv->dev_node ? plat_priv->dev_node : dev->of_node);
+	if (plat_priv->dt_type == CNSS_DTT_MULTIEXCHG) {
+		id_n = of_property_count_strings(dt_node,
+						 WLAN_VREGS_PROP);
+		if (id_n <= 0) {
+			if (id_n == -ENODATA || id_n == -EINVAL) {
+				cnss_pr_dbg("No additional vregs for: %s:%lx\n",
+					    dt_node->name,
+					    plat_priv->device_id);
+				/* 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: %s:%lx\n",
+				    WLAN_VREGS_PROP, dt_node->name,
+				    plat_priv->device_id);
+			return -EINVAL;
+		}
+	} else {
+		id_n = vreg_list_size;
+	}
+
+	for (i = 0; i < id_n; i++) {
+		vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+		if (!vreg)
+			return -ENOMEM;
+
+		if (plat_priv->dt_type == CNSS_DTT_MULTIEXCHG) {
+			ret = of_property_read_string_index(dt_node,
+							    WLAN_VREGS_PROP, i,
+							    &vreg->cfg.name);
+			if (ret) {
+				cnss_pr_err("Failed to read vreg ids\n");
+				return ret;
+			}
+		} else {
+			memcpy(&vreg->cfg, &vreg_cfg[i], sizeof(vreg->cfg));
+		}
+
+		ret = cnss_get_vreg_single(plat_priv, vreg);
+		if (ret != 0) {
+			if (ret == -ENODEV) {
+				devm_kfree(dev, vreg);
+				continue;
+			} else {
+				devm_kfree(dev, vreg);
+				return ret;
+			}
+		}
+		list_add_tail(&vreg->list, vreg_list);
+	}
+
+	return 0;
+}
+
+static void cnss_put_vreg(struct cnss_plat_data *plat_priv,
+			  struct list_head *vreg_list)
+{
+	struct cnss_vreg_info *vreg;
+
+	while (!list_empty(vreg_list)) {
+		vreg = list_first_entry(vreg_list,
+					struct cnss_vreg_info, list);
+		list_del(&vreg->list);
+		if (IS_ERR_OR_NULL(vreg->reg))
+			continue;
+		cnss_put_vreg_single(plat_priv, vreg);
+	}
+}
+
+static int cnss_vreg_on(struct cnss_plat_data *plat_priv,
+			struct list_head *vreg_list)
+{
+	struct cnss_vreg_info *vreg;
+	int ret = 0;
+
+	list_for_each_entry(vreg, vreg_list, list) {
+		if (IS_ERR_OR_NULL(vreg->reg))
+			continue;
+		ret = cnss_vreg_on_single(vreg);
+		if (ret)
+			break;
+	}
+
+	if (!ret)
+		return 0;
+
+	list_for_each_entry_continue_reverse(vreg, vreg_list, list) {
+		if (IS_ERR_OR_NULL(vreg->reg) || !vreg->enabled)
+			continue;
+
+		cnss_vreg_off_single(vreg);
+	}
+
+	return ret;
+}
+
+static int cnss_vreg_off(struct cnss_plat_data *plat_priv,
+			 struct list_head *vreg_list)
+{
+	struct cnss_vreg_info *vreg;
+
+	list_for_each_entry_reverse(vreg, vreg_list, list) {
+		if (IS_ERR_OR_NULL(vreg->reg))
+			continue;
+
+		cnss_vreg_off_single(vreg);
+	}
+
+	return 0;
+}
+
+static int cnss_vreg_unvote(struct cnss_plat_data *plat_priv,
+			    struct list_head *vreg_list)
+{
+	struct cnss_vreg_info *vreg;
+
+	list_for_each_entry_reverse(vreg, vreg_list, list) {
+		if (IS_ERR_OR_NULL(vreg->reg))
+			continue;
+
+		if (vreg->cfg.need_unvote)
+			cnss_vreg_unvote_single(vreg);
+	}
+
+	return 0;
+}
+
+int cnss_get_vreg_type(struct cnss_plat_data *plat_priv,
+		       enum cnss_vreg_type type)
+{
+	struct cnss_vreg_cfg *vreg_cfg;
+	u32 vreg_list_size = 0;
+	int ret = 0;
+
+	vreg_cfg = get_vreg_list(&vreg_list_size, type);
+	if (!vreg_cfg)
+		return -EINVAL;
+
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		ret = cnss_get_vreg(plat_priv, &plat_priv->vreg_list,
+				    vreg_cfg, vreg_list_size);
+		break;
+	default:
+		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+void cnss_put_vreg_type(struct cnss_plat_data *plat_priv,
+			enum cnss_vreg_type type)
+{
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		cnss_put_vreg(plat_priv, &plat_priv->vreg_list);
+		break;
+	default:
+		return;
+	}
+}
+
+int cnss_vreg_on_type(struct cnss_plat_data *plat_priv,
+		      enum cnss_vreg_type type)
+{
+	int ret = 0;
+
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		ret = cnss_vreg_on(plat_priv, &plat_priv->vreg_list);
+		break;
+	default:
+		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int cnss_vreg_off_type(struct cnss_plat_data *plat_priv,
+		       enum cnss_vreg_type type)
+{
+	int ret = 0;
+
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		ret = cnss_vreg_off(plat_priv, &plat_priv->vreg_list);
+		break;
+	default:
+		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+int cnss_vreg_unvote_type(struct cnss_plat_data *plat_priv,
+			  enum cnss_vreg_type type)
+{
+	int ret = 0;
+
+	switch (type) {
+	case CNSS_VREG_PRIM:
+		ret = cnss_vreg_unvote(plat_priv, &plat_priv->vreg_list);
+		break;
+	default:
+		cnss_pr_err("Unsupported vreg type 0x%x\n", type);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cnss_get_clk_single(struct cnss_plat_data *plat_priv,
+			       struct cnss_clk_info *clk_info)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+	struct clk *clk;
+	int ret;
+
+	clk = devm_clk_get(dev, clk_info->cfg.name);
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		if (clk_info->cfg.required)
+			cnss_pr_err("Failed to get clock %s, err = %d\n",
+				    clk_info->cfg.name, ret);
+		else
+			cnss_pr_dbg("Failed to get optional clock %s, err = %d\n",
+				    clk_info->cfg.name, ret);
+		return ret;
+	}
+
+	clk_info->clk = clk;
+	cnss_pr_dbg("Got clock: %s, freq: %u\n",
+		    clk_info->cfg.name, clk_info->cfg.freq);
+
+	return 0;
+}
+
+static void cnss_put_clk_single(struct cnss_plat_data *plat_priv,
+				struct cnss_clk_info *clk_info)
+{
+	struct device *dev = &plat_priv->plat_dev->dev;
+
+	cnss_pr_dbg("Put clock: %s\n", clk_info->cfg.name);
+	devm_clk_put(dev, clk_info->clk);
+}
+
+static int cnss_clk_on_single(struct cnss_clk_info *clk_info)
+{
+	int ret;
+
+	if (clk_info->enabled) {
+		cnss_pr_dbg("Clock %s is already enabled\n",
+			    clk_info->cfg.name);
+		return 0;
+	}
+
+	cnss_pr_dbg("Clock %s is being enabled\n", clk_info->cfg.name);
+
+	if (clk_info->cfg.freq) {
+		ret = clk_set_rate(clk_info->clk, clk_info->cfg.freq);
+		if (ret) {
+			cnss_pr_err("Failed to set frequency %u for clock %s, err = %d\n",
+				    clk_info->cfg.freq, clk_info->cfg.name,
+				    ret);
+			return ret;
+		}
+	}
+
+	ret = clk_prepare_enable(clk_info->clk);
+	if (ret) {
+		cnss_pr_err("Failed to enable clock %s, err = %d\n",
+			    clk_info->cfg.name, ret);
+		return ret;
+	}
+
+	clk_info->enabled = true;
+
+	return 0;
+}
+
+static int cnss_clk_off_single(struct cnss_clk_info *clk_info)
+{
+	if (!clk_info->enabled) {
+		cnss_pr_dbg("Clock %s is already disabled\n",
+			    clk_info->cfg.name);
+		return 0;
+	}
+
+	cnss_pr_dbg("Clock %s is being disabled\n", clk_info->cfg.name);
+
+	clk_disable_unprepare(clk_info->clk);
+	clk_info->enabled = false;
+
+	return 0;
+}
+
+int cnss_get_clk(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct list_head *clk_list;
+	struct cnss_clk_info *clk_info;
+	int ret, i;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	dev = &plat_priv->plat_dev->dev;
+	clk_list = &plat_priv->clk_list;
+
+	if (!list_empty(clk_list)) {
+		cnss_pr_dbg("Clocks have already been updated\n");
+		return 0;
+	}
+
+	for (i = 0; i < CNSS_CLK_INFO_SIZE; i++) {
+		clk_info = devm_kzalloc(dev, sizeof(*clk_info), GFP_KERNEL);
+		if (!clk_info) {
+			ret = -ENOMEM;
+			goto cleanup;
+		}
+
+		memcpy(&clk_info->cfg, &cnss_clk_list[i],
+		       sizeof(clk_info->cfg));
+		ret = cnss_get_clk_single(plat_priv, clk_info);
+		if (ret != 0) {
+			if (clk_info->cfg.required) {
+				devm_kfree(dev, clk_info);
+				goto cleanup;
+			} else {
+				devm_kfree(dev, clk_info);
+				continue;
+			}
+		}
+		list_add_tail(&clk_info->list, clk_list);
+	}
+
+	return 0;
+
+cleanup:
+	while (!list_empty(clk_list)) {
+		clk_info = list_first_entry(clk_list, struct cnss_clk_info,
+					    list);
+		list_del(&clk_info->list);
+		if (IS_ERR_OR_NULL(clk_info->clk))
+			continue;
+		cnss_put_clk_single(plat_priv, clk_info);
+		devm_kfree(dev, clk_info);
+	}
+
+	return ret;
+}
+
+void cnss_put_clk(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct list_head *clk_list;
+	struct cnss_clk_info *clk_info;
+
+	if (!plat_priv)
+		return;
+
+	dev = &plat_priv->plat_dev->dev;
+	clk_list = &plat_priv->clk_list;
+
+	while (!list_empty(clk_list)) {
+		clk_info = list_first_entry(clk_list, struct cnss_clk_info,
+					    list);
+		list_del(&clk_info->list);
+		if (IS_ERR_OR_NULL(clk_info->clk))
+			continue;
+		cnss_put_clk_single(plat_priv, clk_info);
+		devm_kfree(dev, clk_info);
+	}
+}
+
+static int cnss_clk_on(struct cnss_plat_data *plat_priv,
+		       struct list_head *clk_list)
+{
+	struct cnss_clk_info *clk_info;
+	int ret = 0;
+
+	list_for_each_entry(clk_info, clk_list, list) {
+		if (IS_ERR_OR_NULL(clk_info->clk))
+			continue;
+		ret = cnss_clk_on_single(clk_info);
+		if (ret)
+			break;
+	}
+
+	if (!ret)
+		return 0;
+
+	list_for_each_entry_continue_reverse(clk_info, clk_list, list) {
+		if (IS_ERR_OR_NULL(clk_info->clk))
+			continue;
+
+		cnss_clk_off_single(clk_info);
+	}
+
+	return ret;
+}
+
+static int cnss_clk_off(struct cnss_plat_data *plat_priv,
+			struct list_head *clk_list)
+{
+	struct cnss_clk_info *clk_info;
+
+	list_for_each_entry_reverse(clk_info, clk_list, list) {
+		if (IS_ERR_OR_NULL(clk_info->clk))
+			continue;
+
+		cnss_clk_off_single(clk_info);
+	}
+
+	return 0;
+}
+
+int cnss_get_pinctrl(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_pinctrl_info *pinctrl_info;
+	u32 gpio_id, i;
+	int gpio_id_n;
+
+	dev = &plat_priv->plat_dev->dev;
+	pinctrl_info = &plat_priv->pinctrl_info;
+
+	pinctrl_info->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) {
+		ret = PTR_ERR(pinctrl_info->pinctrl);
+		cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+		goto out;
+	}
+
+	if (of_find_property(dev->of_node, BOOTSTRAP_GPIO, NULL)) {
+		pinctrl_info->bootstrap_active =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     BOOTSTRAP_ACTIVE);
+		if (IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+			ret = PTR_ERR(pinctrl_info->bootstrap_active);
+			cnss_pr_err("Failed to get bootstrap active state, err = %d\n",
+				    ret);
+			goto out;
+		}
+	}
+
+	if (of_find_property(dev->of_node, HOST_SOL_GPIO, NULL) &&
+	    of_find_property(dev->of_node, DEV_SOL_GPIO, NULL)) {
+		pinctrl_info->sol_default =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     SOL_DEFAULT);
+		if (IS_ERR_OR_NULL(pinctrl_info->sol_default)) {
+			ret = PTR_ERR(pinctrl_info->sol_default);
+			cnss_pr_err("Failed to get sol default state, err = %d\n",
+				    ret);
+			goto out;
+		}
+		cnss_pr_dbg("Got sol default state\n");
+	}
+
+	if (of_find_property(dev->of_node, WLAN_EN_GPIO, NULL)) {
+		pinctrl_info->wlan_en_gpio = of_get_named_gpio(dev->of_node,
+							       WLAN_EN_GPIO, 0);
+		cnss_pr_dbg("WLAN_EN GPIO: %d\n", pinctrl_info->wlan_en_gpio);
+		pinctrl_info->wlan_en_active =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     WLAN_EN_ACTIVE);
+		if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+			ret = PTR_ERR(pinctrl_info->wlan_en_active);
+			cnss_pr_err("Failed to get wlan_en active state, err = %d\n",
+				    ret);
+			goto out;
+		}
+
+		pinctrl_info->wlan_en_sleep =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     WLAN_EN_SLEEP);
+		if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
+			ret = PTR_ERR(pinctrl_info->wlan_en_sleep);
+			cnss_pr_err("Failed to get wlan_en sleep state, err = %d\n",
+				    ret);
+			goto out;
+		}
+
+		cnss_set_feature_list(plat_priv, CNSS_WLAN_EN_SUPPORT_V01);
+	} else {
+		pinctrl_info->wlan_en_gpio = -EINVAL;
+	}
+
+	/* Added for QCA6490 PMU delayed WLAN_EN_GPIO */
+	if (of_find_property(dev->of_node, BT_EN_GPIO, NULL)) {
+		pinctrl_info->bt_en_gpio = of_get_named_gpio(dev->of_node,
+							     BT_EN_GPIO, 0);
+		cnss_pr_dbg("BT GPIO: %d\n", pinctrl_info->bt_en_gpio);
+	} else {
+		pinctrl_info->bt_en_gpio = -EINVAL;
+	}
+
+	/* Added for QCA6490 to minimize XO CLK selection leakage prevention */
+	if (of_find_property(dev->of_node, XO_CLK_GPIO, NULL)) {
+		pinctrl_info->xo_clk_gpio = of_get_named_gpio(dev->of_node,
+							      XO_CLK_GPIO, 0);
+		cnss_pr_dbg("QCA6490 XO_CLK GPIO: %d\n",
+			    pinctrl_info->xo_clk_gpio);
+		cnss_set_feature_list(plat_priv, BOOTSTRAP_CLOCK_SELECT_V01);
+	} else {
+		pinctrl_info->xo_clk_gpio = -EINVAL;
+	}
+
+	if (of_find_property(dev->of_node, SW_CTRL_GPIO, NULL)) {
+		pinctrl_info->sw_ctrl_gpio = of_get_named_gpio(dev->of_node,
+							       SW_CTRL_GPIO,
+							       0);
+		cnss_pr_dbg("Switch control GPIO: %d\n",
+			    pinctrl_info->sw_ctrl_gpio);
+
+		pinctrl_info->sw_ctrl =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     "sw_ctrl");
+		if (IS_ERR_OR_NULL(pinctrl_info->sw_ctrl)) {
+			ret = PTR_ERR(pinctrl_info->sw_ctrl);
+			cnss_pr_dbg("Failed to get sw_ctrl state, err = %d\n",
+				    ret);
+		} else {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->sw_ctrl);
+			if (ret)
+				cnss_pr_err("Failed to select sw_ctrl state, err = %d\n",
+					    ret);
+		}
+	} else {
+		pinctrl_info->sw_ctrl_gpio = -EINVAL;
+	}
+
+	if (of_find_property(dev->of_node, WLAN_SW_CTRL_GPIO, NULL)) {
+		pinctrl_info->sw_ctrl_wl_cx =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     "sw_ctrl_wl_cx");
+		if (IS_ERR_OR_NULL(pinctrl_info->sw_ctrl_wl_cx)) {
+			ret = PTR_ERR(pinctrl_info->sw_ctrl_wl_cx);
+			cnss_pr_dbg("Failed to get sw_ctrl_wl_cx state, err = %d\n",
+				    ret);
+		} else {
+
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->sw_ctrl_wl_cx);
+			if (ret)
+				cnss_pr_err("Failed to select sw_ctrl_wl_cx state, err = %d\n",
+					    ret);
+		}
+	}
+
+	/* Find out and configure all those GPIOs which need to be setup
+	 * for interrupt wakeup capable
+	 */
+	gpio_id_n = of_property_count_u32_elems(dev->of_node, "mpm_wake_set_gpios");
+	if (gpio_id_n > 0) {
+		cnss_pr_dbg("Num of GPIOs to be setup for interrupt wakeup capable: %d\n",
+			    gpio_id_n);
+		for (i = 0; i < gpio_id_n; i++) {
+			ret = of_property_read_u32_index(dev->of_node,
+							 "mpm_wake_set_gpios",
+							 i, &gpio_id);
+			if (ret) {
+				cnss_pr_err("Failed to read gpio_id at index: %d\n", i);
+				continue;
+			}
+
+			ret = msm_gpio_mpm_wake_set(gpio_id, 1);
+			if (ret < 0) {
+				cnss_pr_err("Failed to setup gpio_id: %d as interrupt wakeup capable, ret: %d\n",
+					    ret);
+			} else {
+				cnss_pr_dbg("gpio_id: %d successfully setup for interrupt wakeup capable\n",
+					    gpio_id);
+			}
+		}
+	} else {
+		cnss_pr_dbg("No GPIOs to be setup for interrupt wakeup capable\n");
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_get_wlan_sw_ctrl(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct cnss_pinctrl_info *pinctrl_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	pinctrl_info = &plat_priv->pinctrl_info;
+
+	if (of_find_property(dev->of_node, WLAN_SW_CTRL_GPIO, NULL)) {
+		pinctrl_info->wlan_sw_ctrl_gpio = of_get_named_gpio(dev->of_node,
+								    WLAN_SW_CTRL_GPIO,
+								    0);
+		cnss_pr_dbg("WLAN Switch control GPIO: %d\n",
+			    pinctrl_info->wlan_sw_ctrl_gpio);
+	} else {
+		pinctrl_info->wlan_sw_ctrl_gpio = -EINVAL;
+	}
+
+	return 0;
+}
+
+#define CNSS_XO_CLK_RETRY_COUNT_MAX 5
+static void cnss_set_xo_clk_gpio_state(struct cnss_plat_data *plat_priv,
+				       bool enable)
+{
+	int xo_clk_gpio = plat_priv->pinctrl_info.xo_clk_gpio, retry = 0, ret;
+
+	if (xo_clk_gpio < 0 || plat_priv->device_id != QCA6490_DEVICE_ID)
+		return;
+
+retry_gpio_req:
+	ret = gpio_request(xo_clk_gpio, "XO_CLK_GPIO");
+	if (ret) {
+		if (retry++ < CNSS_XO_CLK_RETRY_COUNT_MAX) {
+			/* wait for ~(10 - 20) ms */
+			usleep_range(10000, 20000);
+			goto retry_gpio_req;
+		}
+	}
+
+	if (ret) {
+		cnss_pr_err("QCA6490 XO CLK Gpio request failed\n");
+		return;
+	}
+
+	if (enable) {
+		gpio_direction_output(xo_clk_gpio, 1);
+		/*XO CLK must be asserted for some time before WLAN_EN */
+		usleep_range(100, 200);
+	} else {
+		/* Assert XO CLK ~(2-5)ms before off for valid latch in HW */
+		usleep_range(2000, 5000);
+		gpio_direction_output(xo_clk_gpio, 0);
+	}
+
+	gpio_free(xo_clk_gpio);
+}
+
+int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
+			      bool state)
+{
+	int ret = 0;
+	struct cnss_pinctrl_info *pinctrl_info;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	pinctrl_info = &plat_priv->pinctrl_info;
+
+	if (state) {
+		if (!IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+			ret = pinctrl_select_state
+				(pinctrl_info->pinctrl,
+				 pinctrl_info->bootstrap_active);
+			if (ret) {
+				cnss_pr_err("Failed to select bootstrap active state, err = %d\n",
+					    ret);
+				goto out;
+			}
+			udelay(BOOTSTRAP_DELAY);
+		}
+		if (!IS_ERR_OR_NULL(pinctrl_info->sol_default)) {
+			ret = pinctrl_select_state
+				(pinctrl_info->pinctrl,
+				 pinctrl_info->sol_default);
+			if (ret) {
+				cnss_pr_err("Failed to select sol default state, err = %d\n",
+					    ret);
+				goto out;
+			}
+			cnss_pr_dbg("Selected sol default state\n");
+		}
+		cnss_set_xo_clk_gpio_state(plat_priv, true);
+		if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+			ret = pinctrl_select_state
+				(pinctrl_info->pinctrl,
+				 pinctrl_info->wlan_en_active);
+			if (ret) {
+				cnss_pr_err("Failed to select wlan_en active state, err = %d\n",
+					    ret);
+				goto out;
+			}
+
+			if (plat_priv->device_id == QCA6174_DEVICE_ID ||
+			    plat_priv->device_id == 0)
+				mdelay(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);
+			if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+				cnss_pr_dbg("Avoid WLAN_EN low. WLAN HW Disbaled");
+				goto out;
+			}
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->wlan_en_sleep);
+			if (ret) {
+				cnss_pr_err("Failed to select wlan_en sleep state, err = %d\n",
+					    ret);
+				goto out;
+			}
+		} else {
+			goto out;
+		}
+	}
+
+	cnss_pr_dbg("WLAN_EN Value: %d\n", gpio_get_value(pinctrl_info->wlan_en_gpio));
+	cnss_pr_dbg("%s WLAN_EN GPIO successfully\n",
+		    state ? "Assert" : "De-assert");
+
+	return 0;
+out:
+	return ret;
+}
+
+/**
+ * cnss_select_pinctrl_enable - select WLAN_GPIO for Active pinctrl status
+ * @plat_priv: Platform private data structure pointer
+ *
+ * For QCA6490, PMU requires minimum 100ms delay between BT_EN_GPIO off and
+ * WLAN_EN_GPIO on. This is done to avoid power up issues.
+ *
+ * Return: Status of pinctrl select operation. 0 - Success.
+ */
+int cnss_select_pinctrl_enable(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0, bt_en_gpio = plat_priv->pinctrl_info.bt_en_gpio;
+	u8 wlan_en_state = 0;
+
+	if (bt_en_gpio < 0 || plat_priv->device_id != QCA6490_DEVICE_ID)
+		goto set_wlan_en;
+
+	if (gpio_get_value(bt_en_gpio)) {
+		cnss_pr_dbg("BT_EN_GPIO State: On\n");
+		ret = cnss_select_pinctrl_state(plat_priv, true);
+		if (!ret)
+			return ret;
+		wlan_en_state = 1;
+	}
+	if (!gpio_get_value(bt_en_gpio)) {
+		cnss_pr_dbg("BT_EN_GPIO State: Off. Delay WLAN_GPIO enable\n");
+		/* check for BT_EN_GPIO down race during above operation */
+		if (wlan_en_state) {
+			cnss_pr_dbg("Reset WLAN_EN as BT got turned off during enable\n");
+			cnss_select_pinctrl_state(plat_priv, false);
+			wlan_en_state = 0;
+		}
+		/* 100 ms delay for BT_EN and WLAN_EN QCA6490 PMU sequencing */
+		msleep(100);
+	}
+set_wlan_en:
+	if (!wlan_en_state)
+		ret = cnss_select_pinctrl_state(plat_priv, true);
+	return ret;
+}
+
+int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num)
+{
+	int ret;
+
+	if (gpio_num < 0)
+		return -EINVAL;
+
+	ret = gpio_direction_input(gpio_num);
+	if (ret) {
+		cnss_pr_err("Failed to set direction of GPIO(%d), err = %d",
+			    gpio_num, ret);
+		return -EINVAL;
+	}
+
+	return gpio_get_value(gpio_num);
+}
+
+int cnss_power_on_device(struct cnss_plat_data *plat_priv, bool reset)
+{
+	int ret = 0;
+	int dsp_link_status = -1;
+
+	if (plat_priv->powered_on) {
+		cnss_pr_dbg("Already powered up");
+		return 0;
+	}
+
+	cnss_wlan_hw_disable_check(plat_priv);
+	if (test_bit(CNSS_WLAN_HW_DISABLED, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Avoid WLAN Power On. WLAN HW Disbaled");
+		return -EINVAL;
+	}
+
+	/* For PCIe switch platform, disable DSP downstream link before power
+	 * on/off wlan device to avoid uncorrectable AER erro on DSP side.
+	 */
+	cnss_bus_set_dsp_link_status(plat_priv, true);
+	cnss_bus_dsp_link_control(plat_priv, false);
+
+	ret = cnss_vreg_on_type(plat_priv, CNSS_VREG_PRIM);
+	if (ret) {
+		cnss_pr_err("Failed to turn on vreg, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_clk_on(plat_priv, &plat_priv->clk_list);
+	if (ret) {
+		cnss_pr_err("Failed to turn on clocks, err = %d\n", ret);
+		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);
+		goto clk_off;
+	}
+
+	/* For PCIe switch platform, wait for link train of DSP<->WLAN complete
+	 */
+	dsp_link_status = cnss_bus_get_dsp_link_status(plat_priv);
+	if (dsp_link_status == PCI_DSP_LINK_DISABLE) {
+		ret = cnss_bus_dsp_link_enable(plat_priv);
+		if (ret) {
+			cnss_pr_err("Failed to enable bus dsp link, err = %d\n", ret);
+			goto clk_off;
+		}
+	}
+
+	plat_priv->powered_on = true;
+	clear_bit(CNSS_POWER_OFF, &plat_priv->driver_state);
+	cnss_enable_dev_sol_irq(plat_priv);
+	cnss_set_host_sol_value(plat_priv, 0);
+
+	return 0;
+
+clk_off:
+	cnss_clk_off(plat_priv, &plat_priv->clk_list);
+vreg_off:
+	cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM);
+out:
+	return ret;
+}
+
+void cnss_power_off_device(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv->powered_on) {
+		cnss_pr_dbg("Already powered down");
+		return;
+	}
+
+	cnss_bus_dsp_link_control(plat_priv, false);
+	set_bit(CNSS_POWER_OFF, &plat_priv->driver_state);
+	cnss_bus_shutdown_cleanup(plat_priv);
+	cnss_disable_dev_sol_irq(plat_priv);
+	cnss_select_pinctrl_state(plat_priv, false);
+	cnss_clk_off(plat_priv, &plat_priv->clk_list);
+	cnss_vreg_off_type(plat_priv, CNSS_VREG_PRIM);
+	plat_priv->powered_on = false;
+}
+
+bool cnss_is_device_powered_on(struct cnss_plat_data *plat_priv)
+{
+	return plat_priv->powered_on;
+}
+
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv)
+{
+	unsigned long pin_status = 0;
+
+	set_bit(CNSS_WLAN_EN, &pin_status);
+	set_bit(CNSS_PCIE_TXN, &pin_status);
+	set_bit(CNSS_PCIE_TXP, &pin_status);
+	set_bit(CNSS_PCIE_RXN, &pin_status);
+	set_bit(CNSS_PCIE_RXP, &pin_status);
+	set_bit(CNSS_PCIE_REFCLKN, &pin_status);
+	set_bit(CNSS_PCIE_REFCLKP, &pin_status);
+	set_bit(CNSS_PCIE_RST, &pin_status);
+
+	plat_priv->pin_result.host_pin_result = pin_status;
+}
+
+#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
+static int cnss_cmd_db_ready(struct cnss_plat_data *plat_priv)
+{
+	return cmd_db_ready();
+}
+
+static u32 cnss_cmd_db_read_addr(struct cnss_plat_data *plat_priv,
+				 const char *res_id)
+{
+	return cmd_db_read_addr(res_id);
+}
+#else
+static int cnss_cmd_db_ready(struct cnss_plat_data *plat_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+static u32 cnss_cmd_db_read_addr(struct cnss_plat_data *plat_priv,
+				 const char *res_id)
+{
+	return 0;
+}
+#endif
+
+int cnss_get_tcs_info(struct cnss_plat_data *plat_priv)
+{
+	struct platform_device *plat_dev = plat_priv->plat_dev;
+	struct resource *res;
+	resource_size_t addr_len;
+	void __iomem *tcs_cmd_base_addr;
+	int ret = 0;
+
+	res = platform_get_resource_byname(plat_dev, IORESOURCE_MEM, "tcs_cmd");
+	if (!res) {
+		cnss_pr_dbg("TCS CMD address is not present for CPR\n");
+		goto out;
+	}
+
+	plat_priv->tcs_info.cmd_base_addr = res->start;
+	addr_len = resource_size(res);
+	cnss_pr_dbg("TCS CMD base address is %pa with length %pa\n",
+		    &plat_priv->tcs_info.cmd_base_addr, &addr_len);
+
+	tcs_cmd_base_addr = devm_ioremap(&plat_dev->dev, res->start, addr_len);
+	if (!tcs_cmd_base_addr) {
+		ret = -EINVAL;
+		cnss_pr_err("Failed to map TCS CMD address, err = %d\n",
+			    ret);
+		goto out;
+	}
+	plat_priv->tcs_info.cmd_base_addr_io = tcs_cmd_base_addr;
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_get_cpr_info(struct cnss_plat_data *plat_priv)
+{
+	struct platform_device *plat_dev = plat_priv->plat_dev;
+	struct cnss_cpr_info *cpr_info = &plat_priv->cpr_info;
+	const char *cmd_db_name;
+	u32 cpr_pmic_addr = 0;
+	int ret = 0;
+
+	if (plat_priv->tcs_info.cmd_base_addr == 0) {
+		cnss_pr_dbg("TCS CMD not configured\n");
+		return 0;
+	}
+
+	ret = of_property_read_string(plat_dev->dev.of_node,
+				      "qcom,cmd_db_name", &cmd_db_name);
+	if (ret) {
+		cnss_pr_dbg("CommandDB name is not present for CPR\n");
+		goto out;
+	}
+
+	ret = cnss_cmd_db_ready(plat_priv);
+	if (ret) {
+		cnss_pr_err("CommandDB is not ready, err = %d\n", ret);
+		goto out;
+	}
+
+	cpr_pmic_addr = cnss_cmd_db_read_addr(plat_priv, cmd_db_name);
+	if (cpr_pmic_addr > 0) {
+		cpr_info->cpr_pmic_addr = cpr_pmic_addr;
+		cnss_pr_dbg("Get CPR PMIC address 0x%x from %s\n",
+			    cpr_info->cpr_pmic_addr, cmd_db_name);
+	} else {
+		cnss_pr_err("CPR PMIC address is not available for %s\n",
+			    cmd_db_name);
+		ret = -EINVAL;
+		goto out;
+	}
+	return 0;
+out:
+	return ret;
+}
+
+#if IS_ENABLED(CONFIG_MSM_QMP)
+/**
+ * cnss_mbox_init: Initialize mbox interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Try to get property 'mboxes' from device tree and
+ * initialize the interface for AOP configuration.
+ *
+ * Return: 0 for success, otherwise error code
+ */
+static int cnss_mbox_init(struct cnss_plat_data *plat_priv)
+{
+	struct mbox_client *mbox = &plat_priv->mbox_client_data;
+	struct mbox_chan *chan;
+	int ret = 0;
+
+	plat_priv->mbox_chan = NULL;
+	mbox->dev = &plat_priv->plat_dev->dev;
+	mbox->tx_block = true;
+	mbox->tx_tout = CNSS_MBOX_TIMEOUT_MS;
+	mbox->knows_txdone = false;
+	chan = mbox_request_channel(mbox, 0);
+	if (IS_ERR(chan)) {
+		ret = PTR_ERR(chan);
+		cnss_pr_dbg("Failed to get mbox channel[%d]\n", ret);
+	} else {
+		plat_priv->mbox_chan = chan;
+		cnss_pr_dbg("Mbox channel initialized\n");
+	}
+
+	return ret;
+}
+
+/**
+ * cnss_mbox_deinit: De-Initialize mbox interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Return: None
+ */
+static void cnss_mbox_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv->mbox_chan) {
+		mbox_free_channel(plat_priv->mbox_chan);
+		plat_priv->mbox_chan = NULL;
+	}
+}
+
+/**
+ * cnss_mbox_send_msg: Send json message to AOP using mbox channel
+ * @plat_priv: Pointer to cnss platform data
+ * @msg: String in json format
+ *
+ * Return: 0 for success, otherwise error code
+ */
+static int
+cnss_mbox_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
+{
+	struct qmp_pkt pkt;
+	int mbox_msg_size;
+	int ret = 0;
+
+	if (!plat_priv->mbox_chan)
+		return -ENODEV;
+
+	mbox_msg_size = strlen(mbox_msg) + 1;
+
+	if (mbox_msg_size > CNSS_MBOX_MSG_MAX_LEN) {
+		cnss_pr_err("message length greater than max length\n");
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Sending AOP Mbox msg: %s\n", mbox_msg);
+	pkt.size = mbox_msg_size;
+	pkt.data = mbox_msg;
+	ret = mbox_send_message(plat_priv->mbox_chan, &pkt);
+	if (ret < 0)
+		cnss_pr_err("Failed to send AOP mbox msg: %s\n", mbox_msg);
+	else
+		ret = 0;
+
+	return ret;
+}
+#else
+static inline int cnss_mbox_init(struct cnss_plat_data *plat_priv)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void cnss_mbox_deinit(struct cnss_plat_data *plat_priv)
+{
+}
+
+static inline int
+cnss_mbox_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
+/**
+ * cnss_qmp_init: Initialize direct QMP interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Try to get property 'qcom,qmp' from device tree and
+ * initialize the interface for AOP configuration.
+ *
+ * Return: 0 for success, otherwise error code
+ */
+static int cnss_qmp_init(struct cnss_plat_data *plat_priv)
+{
+	struct qmp *qmp;
+
+	plat_priv->qmp = NULL;
+	qmp = qmp_get(&plat_priv->plat_dev->dev);
+	if (IS_ERR(qmp)) {
+		cnss_pr_err("Failed to get qmp: %d\n",
+			    PTR_ERR(qmp));
+		return PTR_ERR(qmp);
+	}
+
+	plat_priv->qmp = qmp;
+	cnss_pr_dbg("QMP initialized\n");
+	return 0;
+}
+
+/**
+ * cnss_qmp_deinit: De-Initialize direct QMP interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Return: None
+ */
+static void cnss_qmp_deinit(struct cnss_plat_data *plat_priv)
+{
+	if (plat_priv->qmp) {
+		qmp_put(plat_priv->qmp);
+		plat_priv->qmp = NULL;
+	}
+}
+
+/**
+ * cnss_qmp_send_msg: Send json message to AOP using direct QMP
+ * @plat_priv: Pointer to cnss platform data
+ * @msg: String in json format
+ *
+ * Return: 0 for success, otherwise error code
+ */
+static int
+cnss_qmp_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
+{
+	int ret;
+
+	if (!plat_priv->qmp)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending AOP QMP msg: %s\n", mbox_msg);
+	ret = qmp_send(plat_priv->qmp, mbox_msg, CNSS_MBOX_MSG_MAX_LEN);
+	if (ret)
+		cnss_pr_err("Failed to send AOP QMP msg: %d[%s]\n", ret, mbox_msg);
+
+	return ret;
+}
+
+/**
+ * cnss_aop_interface_init: Initialize AOP interface: either mbox channel or direct QMP
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Device tree file should have either mbox or qmp configured, but not both.
+ * Based on device tree configuration setup mbox channel or QMP
+ *
+ * Return: 0 for success, otherwise error code
+ */
+int cnss_aop_interface_init(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	/* First try to get mbox channel, if it fails then try qmp_get
+	 * In device tree file there should be either mboxes or qmp,
+	 * cannot have both properties at the same time.
+	 */
+	ret = cnss_mbox_init(plat_priv);
+	if (ret) {
+		ret = cnss_qmp_init(plat_priv);
+		if (ret)
+			return ret;
+	}
+
+	ret = cnss_aop_pdc_reconfig(plat_priv);
+	if (ret)
+		cnss_pr_err("Failed to reconfig WLAN PDC, err = %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * cnss_aop_interface_deinit: Cleanup AOP interface
+ * @plat_priv: Pointer to cnss platform data
+ *
+ * Cleanup mbox channel or QMP whichever was configured during initialization.
+ *
+ * Return: None
+ */
+void cnss_aop_interface_deinit(struct cnss_plat_data *plat_priv)
+{
+	cnss_mbox_deinit(plat_priv);
+	cnss_qmp_deinit(plat_priv);
+}
+
+/**
+ * cnss_aop_send_msg: Sends json message to AOP using either mbox channel or direct QMP
+ * @plat_priv: Pointer to cnss platform data
+ * @msg: String in json format
+ *
+ * AOP accepts JSON message to configure WLAN resources. Format as follows:
+ * To send VReg config: {class: wlan_pdc, ss: <pdc_name>,
+ *                       res: <VReg_name>.<param>, <seq_param>: <value>}
+ * To send PDC Config: {class: wlan_pdc, ss: <pdc_name>, res: pdc,
+ *                      enable: <Value>}
+ * QMP returns timeout error if format not correct or AOP operation fails.
+ *
+ * Return: 0 for success
+ */
+int cnss_aop_send_msg(struct cnss_plat_data *plat_priv, char *mbox_msg)
+{
+	int ret;
+
+	ret = cnss_mbox_send_msg(plat_priv, mbox_msg);
+	if (ret)
+		ret = cnss_qmp_send_msg(plat_priv, mbox_msg);
+
+	if (ret)
+		cnss_pr_err("Failed to send AOP msg: %d\n", ret);
+	return ret;
+}
+
+static inline bool cnss_aop_interface_ready(struct cnss_plat_data *plat_priv)
+{
+	return (plat_priv->mbox_chan || plat_priv->qmp);
+}
+
+/* cnss_pdc_reconfig: Send PDC init table as configured in DT for wlan device */
+int cnss_aop_pdc_reconfig(struct cnss_plat_data *plat_priv)
+{
+	u32 i;
+	int ret;
+
+	if (plat_priv->pdc_init_table_len <= 0 || !plat_priv->pdc_init_table)
+		return 0;
+
+	cnss_pr_dbg("Setting PDC defaults for device ID: %d\n",
+		    plat_priv->device_id);
+	for (i = 0; i < plat_priv->pdc_init_table_len; i++) {
+		ret = cnss_aop_send_msg(plat_priv,
+					(char *)plat_priv->pdc_init_table[i]);
+		if (ret < 0)
+			break;
+	}
+	return ret;
+}
+
+/* cnss_aop_pdc_name_str: Get PDC name corresponding to VReg from DT Mapiping */
+static const char *cnss_aop_pdc_name_str(struct cnss_plat_data *plat_priv,
+					 const char *vreg_name)
+{
+	u32 i;
+	static const char * const aop_pdc_ss_str[] = {"rf", "bb"};
+	const char *pdc = aop_pdc_ss_str[0], *vreg_map_name;
+
+	if (plat_priv->vreg_pdc_map_len <= 0 || !plat_priv->vreg_pdc_map)
+		goto end;
+
+	for (i = 0; i < plat_priv->vreg_pdc_map_len; i++) {
+		vreg_map_name = plat_priv->vreg_pdc_map[i];
+		if (strnstr(vreg_map_name, vreg_name, strlen(vreg_map_name))) {
+			pdc = plat_priv->vreg_pdc_map[i + 1];
+			break;
+		}
+	}
+end:
+	cnss_pr_dbg("%s mapped to %s\n", vreg_name, pdc);
+	return pdc;
+}
+
+static int cnss_aop_set_vreg_param(struct cnss_plat_data *plat_priv,
+				   const char *vreg_name,
+				   enum cnss_aop_vreg_param param,
+				   enum cnss_aop_tcs_seq_param seq_param,
+				   int val)
+{
+	char msg[CNSS_MBOX_MSG_MAX_LEN];
+	static const char * const aop_vreg_param_str[] = {
+		[CNSS_VREG_VOLTAGE] = "v", [CNSS_VREG_MODE] = "m",
+		[CNSS_VREG_ENABLE] = "e",};
+	static const char * const aop_tcs_seq_str[] = {
+		[CNSS_TCS_UP_SEQ] = "upval", [CNSS_TCS_DOWN_SEQ] = "dwnval",
+		[CNSS_TCS_ENABLE_SEQ] = "enable",};
+
+	if (param >= CNSS_VREG_PARAM_MAX || seq_param >= CNSS_TCS_SEQ_MAX ||
+	    !vreg_name)
+		return -EINVAL;
+
+	snprintf(msg, CNSS_MBOX_MSG_MAX_LEN,
+		 "{class: wlan_pdc, ss: %s, res: %s.%s, %s: %d}",
+		 cnss_aop_pdc_name_str(plat_priv, vreg_name),
+		 vreg_name, aop_vreg_param_str[param],
+		 aop_tcs_seq_str[seq_param], val);
+
+	return cnss_aop_send_msg(plat_priv, msg);
+}
+
+int cnss_aop_ol_cpr_cfg_setup(struct cnss_plat_data *plat_priv,
+			      struct wlfw_pmu_cfg_v01 *fw_pmu_cfg)
+{
+	const char *pmu_pin, *vreg;
+	struct wlfw_pmu_param_v01 *fw_pmu_param;
+	u32 fw_pmu_param_len, i, j, plat_vreg_param_len = 0;
+	int ret = 0;
+	struct platform_vreg_param {
+		char vreg[MAX_PROP_SIZE];
+		u32 wake_volt;
+		u32 sleep_volt;
+	} plat_vreg_param[QMI_WLFW_PMU_PARAMS_MAX_V01] = {0};
+	static bool config_done;
+
+	if (config_done)
+		return 0;
+
+	if (plat_priv->pmu_vreg_map_len <= 0 ||
+	    !plat_priv->pmu_vreg_map ||
+	    (!plat_priv->mbox_chan && !plat_priv->qmp)) {
+		cnss_pr_dbg("Mbox channel / QMP / PMU VReg Map not configured\n");
+		goto end;
+	}
+
+	if (!fw_pmu_cfg)
+		return -EINVAL;
+
+	fw_pmu_param = fw_pmu_cfg->pmu_param;
+	fw_pmu_param_len = fw_pmu_cfg->pmu_param_len;
+	/* Get PMU Pin name to Platfom Vreg Mapping */
+	for (i = 0; i < fw_pmu_param_len; i++) {
+		cnss_pr_dbg("FW_PMU Data: %s %d %d %d %d\n",
+			    fw_pmu_param[i].pin_name,
+			    fw_pmu_param[i].wake_volt_valid,
+			    fw_pmu_param[i].wake_volt,
+			    fw_pmu_param[i].sleep_volt_valid,
+			    fw_pmu_param[i].sleep_volt);
+
+		if (!fw_pmu_param[i].wake_volt_valid &&
+		    !fw_pmu_param[i].sleep_volt_valid)
+			continue;
+
+		vreg = NULL;
+		for (j = 0; j < plat_priv->pmu_vreg_map_len; j += 2) {
+			pmu_pin = plat_priv->pmu_vreg_map[j];
+			if (strnstr(pmu_pin, fw_pmu_param[i].pin_name,
+				    strlen(pmu_pin))) {
+				vreg = plat_priv->pmu_vreg_map[j + 1];
+				break;
+			}
+		}
+		if (!vreg) {
+			cnss_pr_err("No VREG mapping for %s\n",
+				    fw_pmu_param[i].pin_name);
+			continue;
+		} else {
+			cnss_pr_dbg("%s mapped to %s\n",
+				    fw_pmu_param[i].pin_name, vreg);
+		}
+		for (j = 0; j < QMI_WLFW_PMU_PARAMS_MAX_V01; j++) {
+			u32 wake_volt = 0, sleep_volt = 0;
+
+			if (plat_vreg_param[j].vreg[0] == '\0')
+				strlcpy(plat_vreg_param[j].vreg, vreg,
+					sizeof(plat_vreg_param[j].vreg));
+			else if (!strnstr(plat_vreg_param[j].vreg, vreg,
+					  strlen(plat_vreg_param[j].vreg)))
+				continue;
+
+			if (fw_pmu_param[i].wake_volt_valid)
+				wake_volt = roundup(fw_pmu_param[i].wake_volt,
+						    CNSS_PMIC_VOLTAGE_STEP) -
+						    CNSS_PMIC_AUTO_HEADROOM +
+						    CNSS_IR_DROP_WAKE;
+			if (fw_pmu_param[i].sleep_volt_valid)
+				sleep_volt = roundup(fw_pmu_param[i].sleep_volt,
+						     CNSS_PMIC_VOLTAGE_STEP) -
+						     CNSS_PMIC_AUTO_HEADROOM +
+						     CNSS_IR_DROP_SLEEP;
+
+			plat_vreg_param[j].wake_volt =
+				(wake_volt > plat_vreg_param[j].wake_volt ?
+				 wake_volt : plat_vreg_param[j].wake_volt);
+			plat_vreg_param[j].sleep_volt =
+				(sleep_volt > plat_vreg_param[j].sleep_volt ?
+				 sleep_volt : plat_vreg_param[j].sleep_volt);
+
+			plat_vreg_param_len = (plat_vreg_param_len > j ?
+					       plat_vreg_param_len : j);
+			cnss_pr_dbg("Plat VReg Data: %s %d %d\n",
+				    plat_vreg_param[j].vreg,
+				    plat_vreg_param[j].wake_volt,
+				    plat_vreg_param[j].sleep_volt);
+			break;
+		}
+	}
+
+	for (i = 0; i <= plat_vreg_param_len; i++) {
+		if (plat_vreg_param[i].wake_volt > 0) {
+			ret =
+			cnss_aop_set_vreg_param(plat_priv,
+						plat_vreg_param[i].vreg,
+						CNSS_VREG_VOLTAGE,
+						CNSS_TCS_UP_SEQ,
+						plat_vreg_param[i].wake_volt);
+		}
+		if (plat_vreg_param[i].sleep_volt > 0) {
+			ret =
+			cnss_aop_set_vreg_param(plat_priv,
+						plat_vreg_param[i].vreg,
+						CNSS_VREG_VOLTAGE,
+						CNSS_TCS_DOWN_SEQ,
+						plat_vreg_param[i].sleep_volt);
+		}
+		if (ret < 0)
+			break;
+	}
+end:
+	config_done = true;
+	return ret;
+}
+
+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 =
+				of_property_count_strings(dev->of_node,
+							  "qcom,pdc_init_table");
+	if (plat_priv->pdc_init_table_len > 0) {
+		plat_priv->pdc_init_table =
+			kcalloc(plat_priv->pdc_init_table_len,
+				sizeof(char *), GFP_KERNEL);
+		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");
+	}
+
+	plat_priv->vreg_pdc_map_len =
+			of_property_count_strings(dev->of_node,
+						  "qcom,vreg_pdc_map");
+	if (plat_priv->vreg_pdc_map_len > 0) {
+		plat_priv->vreg_pdc_map =
+			kcalloc(plat_priv->vreg_pdc_map_len,
+				sizeof(char *), GFP_KERNEL);
+		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");
+	}
+
+	plat_priv->pmu_vreg_map_len =
+			of_property_count_strings(dev->of_node,
+						  "qcom,pmu_vreg_map");
+	if (plat_priv->pmu_vreg_map_len > 0) {
+		plat_priv->pmu_vreg_map = kcalloc(plat_priv->pmu_vreg_map_len,
+						  sizeof(char *), GFP_KERNEL);
+		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");
+	}
+
+	/* Device DT Specific */
+	if (plat_priv->device_id == QCA6390_DEVICE_ID ||
+	    plat_priv->device_id == QCA6490_DEVICE_ID) {
+		ret = of_property_read_string(dev->of_node,
+					      "qcom,vreg_ol_cpr",
+					      &plat_priv->vreg_ol_cpr);
+		if (ret)
+			cnss_pr_dbg("VReg for QCA6490 OL CPR not configured\n");
+
+		ret = of_property_read_string(dev->of_node,
+					      "qcom,vreg_ipa",
+					      &plat_priv->vreg_ipa);
+		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)
+{
+	struct cnss_cpr_info *cpr_info = &plat_priv->cpr_info;
+	u32 pmic_addr, voltage = 0, voltage_tmp, offset;
+	void __iomem *tcs_cmd_addr, *tcs_cmd_data_addr;
+	int i, j;
+
+	if (cpr_info->voltage == 0) {
+		cnss_pr_err("OL CPR Voltage %dm is not valid\n",
+			    cpr_info->voltage);
+		return -EINVAL;
+	}
+
+	if (plat_priv->device_id != QCA6490_DEVICE_ID)
+		return -EINVAL;
+
+	if (!plat_priv->vreg_ol_cpr ||
+	    !cnss_aop_interface_ready(plat_priv)) {
+		cnss_pr_dbg("AOP interface / OL CPR Vreg not configured\n");
+	} else {
+		return cnss_aop_set_vreg_param(plat_priv,
+					       plat_priv->vreg_ol_cpr,
+					       CNSS_VREG_VOLTAGE,
+					       CNSS_TCS_DOWN_SEQ,
+					       cpr_info->voltage);
+	}
+
+	if (plat_priv->tcs_info.cmd_base_addr == 0) {
+		cnss_pr_dbg("TCS CMD not configured for OL CPR update\n");
+		return 0;
+	}
+
+	if (cpr_info->cpr_pmic_addr == 0) {
+		cnss_pr_err("PMIC address 0x%x is not valid\n",
+			    cpr_info->cpr_pmic_addr);
+		return -EINVAL;
+	}
+
+	if (cpr_info->tcs_cmd_data_addr_io)
+		goto update_cpr;
+
+	for (i = 0; i < MAX_TCS_NUM; i++) {
+		for (j = 0; j < MAX_TCS_CMD_NUM; j++) {
+			offset = i * TCS_OFFSET + j * TCS_CMD_OFFSET;
+			tcs_cmd_addr = plat_priv->tcs_info.cmd_base_addr_io +
+									offset;
+			pmic_addr = readl_relaxed(tcs_cmd_addr);
+			if (pmic_addr == cpr_info->cpr_pmic_addr) {
+				tcs_cmd_data_addr = tcs_cmd_addr +
+					TCS_CMD_DATA_ADDR_OFFSET;
+				voltage_tmp = readl_relaxed(tcs_cmd_data_addr);
+				cnss_pr_dbg("Got voltage %dmV from i: %d, j: %d\n",
+					    voltage_tmp, i, j);
+
+				if (voltage_tmp > voltage) {
+					voltage = voltage_tmp;
+					cpr_info->tcs_cmd_data_addr =
+					plat_priv->tcs_info.cmd_base_addr +
+					offset + TCS_CMD_DATA_ADDR_OFFSET;
+					cpr_info->tcs_cmd_data_addr_io =
+						tcs_cmd_data_addr;
+				}
+			}
+		}
+	}
+
+	if (!cpr_info->tcs_cmd_data_addr_io) {
+		cnss_pr_err("Failed to find proper TCS CMD data address\n");
+		return -EINVAL;
+	}
+
+update_cpr:
+	cpr_info->voltage = cpr_info->voltage > BT_CXMX_VOLTAGE_MV ?
+		cpr_info->voltage : BT_CXMX_VOLTAGE_MV;
+	cnss_pr_dbg("Update TCS CMD data address %pa with voltage %dmV\n",
+		    &cpr_info->tcs_cmd_data_addr, cpr_info->voltage);
+	writel_relaxed(cpr_info->voltage, cpr_info->tcs_cmd_data_addr_io);
+
+	return 0;
+}
+
+int cnss_enable_int_pow_amp_vreg(struct cnss_plat_data *plat_priv)
+{
+	struct platform_device *plat_dev = plat_priv->plat_dev;
+	u32 offset, addr_val, data_val;
+	void __iomem *tcs_cmd;
+	int ret;
+	static bool config_done;
+
+	if (plat_priv->device_id != QCA6490_DEVICE_ID)
+		return -EINVAL;
+
+	if (config_done) {
+		cnss_pr_dbg("IPA Vreg already configured\n");
+		return 0;
+	}
+
+	if (!plat_priv->vreg_ipa ||
+	    !cnss_aop_interface_ready(plat_priv)) {
+		cnss_pr_dbg("AOP interface / IPA Vreg not configured\n");
+	} else {
+		ret = cnss_aop_set_vreg_param(plat_priv,
+					      plat_priv->vreg_ipa,
+					      CNSS_VREG_ENABLE,
+					      CNSS_TCS_UP_SEQ, 1);
+		if (ret == 0)
+			config_done = true;
+		return ret;
+	}
+
+	if (!plat_priv->tcs_info.cmd_base_addr_io) {
+		cnss_pr_err("TCS CMD not configured for IPA Vreg enable\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(plat_dev->dev.of_node,
+				   "qcom,tcs_offset_int_pow_amp_vreg",
+				   &offset);
+	if (ret) {
+		cnss_pr_dbg("Internal Power Amp Vreg not configured\n");
+		return -EINVAL;
+	}
+	tcs_cmd = plat_priv->tcs_info.cmd_base_addr_io + offset;
+	addr_val = readl_relaxed(tcs_cmd);
+	tcs_cmd += TCS_CMD_DATA_ADDR_OFFSET;
+
+	/* 1 = enable Vreg */
+	writel_relaxed(1, tcs_cmd);
+
+	data_val = readl_relaxed(tcs_cmd);
+	cnss_pr_dbg("Setup S3E TCS Addr: %x Data: %d\n", addr_val, data_val);
+	config_done = true;
+
+	return 0;
+}
+
+int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	if (plat_priv->dt_type != CNSS_DTT_MULTIEXCHG)
+		return 0;
+
+	ret = cnss_get_vreg_type(plat_priv, CNSS_VREG_PRIM);
+	if (ret)
+		return ret;
+
+	plat_priv->powered_on = false;
+	return cnss_power_on_device(plat_priv, false);
+}

+ 4158 - 0
qcom/opensource/wlan/platform/cnss2/qmi.c

@@ -0,0 +1,4158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/soc/qcom/qmi.h>
+
+#include "bus.h"
+#include "debug.h"
+#include "main.h"
+#include "qmi.h"
+#include "genl.h"
+
+#define WLFW_SERVICE_INS_ID_V01		1
+#define WLFW_CLIENT_ID			0x4b4e454c
+#define BDF_FILE_NAME_PREFIX		"bdwlan"
+#define ELF_BDF_FILE_NAME		"bdwlan.elf"
+#define ELF_BDF_FILE_NAME_GF		"bdwlang.elf"
+#define ELF_BDF_FILE_NAME_PREFIX	"bdwlan.e"
+#define ELF_BDF_FILE_NAME_GF_PREFIX	"bdwlang.e"
+#define BIN_BDF_FILE_NAME		"bdwlan.bin"
+#define BIN_BDF_FILE_NAME_GF		"bdwlang.bin"
+#define BIN_BDF_FILE_NAME_PREFIX	"bdwlan.b"
+#define BIN_BDF_FILE_NAME_GF_PREFIX	"bdwlang.b"
+#define REGDB_FILE_NAME			"regdb.bin"
+#define HDS_FILE_NAME			"hds.bin"
+#define CHIP_ID_GF_MASK			0x10
+
+#define QDSS_TRACE_CONFIG_FILE		"qdss_trace_config"
+/*
+ * Download QDSS config file based on build type. Add build type string to
+ * file name. Download "qdss_trace_config_debug_v<n>.cfg" for debug build
+ * and "qdss_trace_config_perf_v<n>.cfg" for perf build.
+ */
+#ifdef CONFIG_CNSS2_DEBUG
+#define QDSS_FILE_BUILD_STR		"debug_"
+#else
+#define QDSS_FILE_BUILD_STR		"perf_"
+#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)
+#define COEX_TIMEOUT			QMI_WLFW_TIMEOUT_JF
+#define IMS_TIMEOUT                     QMI_WLFW_TIMEOUT_JF
+
+#define QMI_WLFW_MAX_RECV_BUF_SIZE	SZ_8K
+#define IMSPRIVATE_SERVICE_MAX_MSG_LEN	SZ_8K
+#define DMS_QMI_MAX_MSG_LEN		SZ_256
+#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)
+
+#define QMI_WLFW_MAC_READY_TIMEOUT_MS	50
+#define QMI_WLFW_MAC_READY_MAX_RETRY	200
+
+// these error values are not defined in <linux/soc/qcom/qmi.h> and fw is sending as error response
+#define QMI_ERR_HARDWARE_RESTRICTED_V01		0x0053
+#define QMI_ERR_ENOMEM_V01		0x0002
+
+enum nm_modem_bit {
+	SLEEP_CLOCK_SELECT_INTERNAL_BIT = BIT(1),
+	HOST_CSTATE_BIT = BIT(2),
+};
+
+#ifdef CONFIG_CNSS2_DEBUG
+static bool ignore_qmi_failure;
+#define CNSS_QMI_ASSERT() CNSS_ASSERT(ignore_qmi_failure)
+void cnss_ignore_qmi_failure(bool ignore)
+{
+	ignore_qmi_failure = ignore;
+}
+#else
+#define CNSS_QMI_ASSERT() do { } while (0)
+void cnss_ignore_qmi_failure(bool ignore) { }
+#endif
+
+static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode)
+{
+	switch (mode) {
+	case CNSS_MISSION:
+		return "MISSION";
+	case CNSS_FTM:
+		return "FTM";
+	case CNSS_EPPING:
+		return "EPPING";
+	case CNSS_WALTEST:
+		return "WALTEST";
+	case CNSS_OFF:
+		return "OFF";
+	case CNSS_CCPM:
+		return "CCPM";
+	case CNSS_QVIT:
+		return "QVIT";
+	case CNSS_CALIBRATION:
+		return "CALIBRATION";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static int qmi_send_wait(struct qmi_handle *qmi, void *req, void *rsp,
+			 struct qmi_elem_info *req_ei,
+			 struct qmi_elem_info *rsp_ei,
+			 int req_id, size_t req_len,
+			 unsigned long timeout)
+{
+	struct qmi_txn txn;
+	int ret;
+	char *err_msg;
+	struct qmi_response_type_v01 *resp = rsp;
+
+	ret = qmi_txn_init(qmi, &txn, rsp_ei, rsp);
+	if (ret < 0) {
+		err_msg = "Qmi fail: fail to init txn,";
+		goto out;
+	}
+
+	ret = qmi_send_request(qmi, NULL, &txn, req_id,
+			       req_len, req_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		err_msg = "Qmi fail: fail to send req,";
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, timeout);
+	if (ret < 0) {
+		err_msg = "Qmi fail: wait timeout,";
+		goto out;
+	} else if (resp->result != QMI_RESULT_SUCCESS_V01) {
+		err_msg = "Qmi fail: request rejected,";
+		cnss_pr_err("Qmi fail: respons with error:%d\n",
+			    resp->error);
+		ret = -resp->result;
+		goto out;
+	}
+
+	cnss_pr_dbg("req %x success\n", req_id);
+	return 0;
+out:
+	cnss_pr_err("%s req %x, ret %d\n", err_msg, req_id, ret);
+	return ret;
+}
+
+static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_ind_register_req_msg_v01 *req;
+	struct wlfw_ind_register_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending indication register message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->client_id_valid = 1;
+	req->client_id = WLFW_CLIENT_ID;
+	req->request_mem_enable_valid = 1;
+	req->request_mem_enable = 1;
+	req->fw_mem_ready_enable_valid = 1;
+	req->fw_mem_ready_enable = 1;
+	/* fw_ready indication is replaced by fw_init_done in HST/HSP */
+	req->fw_init_done_enable_valid = 1;
+	req->fw_init_done_enable = 1;
+	req->pin_connect_result_enable_valid = 1;
+	req->pin_connect_result_enable = 1;
+	req->cal_done_enable_valid = 1;
+	req->cal_done_enable = 1;
+	req->qdss_trace_req_mem_enable_valid = 1;
+	req->qdss_trace_req_mem_enable = 1;
+	req->qdss_trace_save_enable_valid = 1;
+	req->qdss_trace_save_enable = 1;
+	req->qdss_trace_free_enable_valid = 1;
+	req->qdss_trace_free_enable = 1;
+	req->respond_get_info_enable_valid = 1;
+	req->respond_get_info_enable = 1;
+	req->wfc_call_twt_config_enable_valid = 1;
+	req->wfc_call_twt_config_enable = 1;
+	req->async_data_enable_valid = 1;
+	req->async_data_enable = 1;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_ind_register_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for indication register request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_IND_REGISTER_REQ_V01,
+			       WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_ind_register_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send indication register request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of indication register request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Indication register request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	if (resp->fw_status_valid) {
+		if (resp->fw_status & QMI_WLFW_ALREADY_REGISTERED_V01) {
+			ret = -EALREADY;
+			goto qmi_registered;
+		}
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+
+qmi_registered:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+static void cnss_wlfw_host_cap_parse_mlo(struct cnss_plat_data *plat_priv,
+					 struct wlfw_host_cap_req_msg_v01 *req)
+{
+	if (plat_priv->device_id == KIWI_DEVICE_ID ||
+	    plat_priv->device_id == MANGO_DEVICE_ID ||
+	    plat_priv->device_id == PEACH_DEVICE_ID) {
+		req->mlo_capable_valid = 1;
+		req->mlo_capable = 1;
+		req->mlo_chip_id_valid = 1;
+		req->mlo_chip_id = 0;
+		req->mlo_group_id_valid = 1;
+		req->mlo_group_id = 0;
+		req->max_mlo_peer_valid = 1;
+		/* Max peer number generally won't change for the same device
+		 * but needs to be synced with host driver.
+		 */
+		req->max_mlo_peer = 32;
+		req->mlo_num_chips_valid = 1;
+		req->mlo_num_chips = 1;
+		req->mlo_chip_info_valid = 1;
+		req->mlo_chip_info[0].chip_id = 0;
+		req->mlo_chip_info[0].num_local_links = 2;
+		req->mlo_chip_info[0].hw_link_id[0] = 0;
+		req->mlo_chip_info[0].hw_link_id[1] = 1;
+		req->mlo_chip_info[0].valid_mlo_link_id[0] = 1;
+		req->mlo_chip_info[0].valid_mlo_link_id[1] = 1;
+	}
+}
+
+static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_host_cap_req_msg_v01 *req;
+	struct wlfw_host_cap_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+	u64 iova_start = 0, iova_size = 0,
+	    iova_ipa_start = 0, iova_ipa_size = 0;
+	u64 feature_list = 0;
+
+	cnss_pr_dbg("Sending host capability message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->num_clients_valid = 1;
+	req->num_clients = 1;
+	cnss_pr_dbg("Number of clients is %d\n", req->num_clients);
+
+	req->wake_msi = cnss_bus_get_wake_irq(plat_priv);
+	if (req->wake_msi) {
+		cnss_pr_dbg("WAKE MSI base data is %d\n", req->wake_msi);
+		req->wake_msi_valid = 1;
+	}
+
+	req->bdf_support_valid = 1;
+	req->bdf_support = 1;
+
+	req->m3_support_valid = 1;
+	req->m3_support = 1;
+
+	req->m3_cache_support_valid = 1;
+	req->m3_cache_support = 1;
+
+	req->cal_done_valid = 1;
+	req->cal_done = plat_priv->cal_done;
+	cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);
+
+	if (plat_priv->sleep_clk) {
+		req->nm_modem_valid = 1;
+		/* Notify firmware about the sleep clock selection,
+		 * nm_modem_bit[1] is used for this purpose.
+		 */
+		req->nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT;
+	}
+
+	if (plat_priv->supported_link_speed) {
+		req->pcie_link_info_valid = 1;
+		req->pcie_link_info.pci_link_speed =
+					plat_priv->supported_link_speed;
+		cnss_pr_dbg("Supported link speed in Host Cap %d\n",
+			    plat_priv->supported_link_speed);
+	}
+
+	if (cnss_bus_is_smmu_s1_enabled(plat_priv) &&
+	    !cnss_bus_get_iova(plat_priv, &iova_start, &iova_size) &&
+	    !cnss_bus_get_iova_ipa(plat_priv, &iova_ipa_start,
+				   &iova_ipa_size)) {
+		req->ddr_range_valid = 1;
+		req->ddr_range[0].start = iova_start;
+		req->ddr_range[0].size = iova_size + iova_ipa_size;
+		cnss_pr_dbg("Sending iova starting 0x%llx with size 0x%llx\n",
+			    req->ddr_range[0].start, req->ddr_range[0].size);
+	}
+
+	req->host_build_type_valid = 1;
+	req->host_build_type = cnss_get_host_build_type();
+
+	cnss_wlfw_host_cap_parse_mlo(plat_priv, req);
+
+	ret = cnss_get_feature_list(plat_priv, &feature_list);
+	if (!ret) {
+		req->feature_list_valid = 1;
+		req->feature_list = feature_list;
+		cnss_pr_dbg("Sending feature list 0x%llx\n",
+			    req->feature_list);
+	}
+
+	if (cnss_get_platform_name(plat_priv, req->platform_name,
+				   QMI_WLFW_MAX_PLATFORM_NAME_LEN_V01))
+		req->platform_name_valid = 1;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_host_cap_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for host capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_HOST_CAP_REQ_V01,
+			       WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_host_cap_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send host capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of host capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Host capability request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_respond_mem_req_msg_v01 *req;
+	struct wlfw_respond_mem_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+	int ret = 0, i;
+
+	cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		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) {
+			if (fw_mem[i].type == 0) {
+				cnss_pr_err("Invalid memory for FW type, segment = %d\n",
+					    i);
+				ret = -EINVAL;
+				goto out;
+			}
+			cnss_pr_err("Memory for FW is not available for type: %u\n",
+				    fw_mem[i].type);
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+			    fw_mem[i].va, &fw_mem[i].pa,
+			    fw_mem[i].size, fw_mem[i].type);
+
+		req->mem_seg[i].addr = fw_mem[i].pa;
+		req->mem_seg[i].size = fw_mem[i].size;
+		req->mem_seg[i].type = fw_mem[i].type;
+	}
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_respond_mem_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for respond memory request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_RESPOND_MEM_REQ_V01,
+			       WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_respond_mem_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send respond memory request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of respond memory request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_cap_req_msg_v01 *req;
+	struct wlfw_cap_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	char *fw_build_timestamp;
+	int ret = 0, i;
+
+	cnss_pr_dbg("Sending target capability message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_cap_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for target capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_CAP_REQ_V01,
+			       WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_cap_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send respond target capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of target capability request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Target capability request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	if (resp->chip_info_valid) {
+		plat_priv->chip_info.chip_id = resp->chip_info.chip_id;
+		plat_priv->chip_info.chip_family = resp->chip_info.chip_family;
+	}
+	if (resp->board_info_valid)
+		plat_priv->board_info.board_id = resp->board_info.board_id;
+	else
+		plat_priv->board_info.board_id = 0xFF;
+	if (resp->soc_info_valid)
+		plat_priv->soc_info.soc_id = resp->soc_info.soc_id;
+	if (resp->fw_version_info_valid) {
+		plat_priv->fw_version_info.fw_version =
+			resp->fw_version_info.fw_version;
+		fw_build_timestamp = resp->fw_version_info.fw_build_timestamp;
+		fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN] = '\0';
+		strlcpy(plat_priv->fw_version_info.fw_build_timestamp,
+			resp->fw_version_info.fw_build_timestamp,
+			QMI_WLFW_MAX_TIMESTAMP_LEN + 1);
+	}
+	if (resp->fw_build_id_valid) {
+		resp->fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN] = '\0';
+		strlcpy(plat_priv->fw_build_id, resp->fw_build_id,
+			QMI_WLFW_MAX_BUILD_ID_LEN + 1);
+	}
+	/* FW will send aop retention volatage for qca6490 */
+	if (resp->voltage_mv_valid) {
+		plat_priv->cpr_info.voltage = resp->voltage_mv;
+		cnss_pr_dbg("Voltage for CPR: %dmV\n",
+			    plat_priv->cpr_info.voltage);
+		cnss_update_cpr_info(plat_priv);
+	}
+	if (resp->time_freq_hz_valid) {
+		plat_priv->device_freq_hz = resp->time_freq_hz;
+		cnss_pr_dbg("Device frequency is %d HZ\n",
+			    plat_priv->device_freq_hz);
+	}
+	if (resp->otp_version_valid)
+		plat_priv->otp_version = resp->otp_version;
+	if (resp->dev_mem_info_valid) {
+		for (i = 0; i < QMI_WLFW_MAX_DEV_MEM_NUM_V01; i++) {
+			plat_priv->dev_mem_info[i].start =
+				resp->dev_mem_info[i].start;
+			plat_priv->dev_mem_info[i].size =
+				resp->dev_mem_info[i].size;
+			cnss_pr_buf("Device memory info[%d]: start = 0x%llx, size = 0x%llx\n",
+				    i, plat_priv->dev_mem_info[i].start,
+				    plat_priv->dev_mem_info[i].size);
+		}
+	}
+	if (resp->fw_caps_valid) {
+		plat_priv->fw_pcie_gen_switch =
+			!!(resp->fw_caps & QMI_WLFW_HOST_PCIE_GEN_SWITCH_V01);
+		plat_priv->fw_aux_uc_support =
+			!!(resp->fw_caps & QMI_WLFW_AUX_UC_SUPPORT_V01);
+		cnss_pr_dbg("FW aux uc support capability: %d\n",
+			    plat_priv->fw_aux_uc_support);
+		plat_priv->fw_caps = resp->fw_caps;
+	}
+
+	if (resp->hang_data_length_valid &&
+	    resp->hang_data_length &&
+	    resp->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE)
+		plat_priv->hang_event_data_len = resp->hang_data_length;
+	else
+		plat_priv->hang_event_data_len = 0;
+
+	if (resp->hang_data_addr_offset_valid)
+		plat_priv->hang_data_addr_offset = resp->hang_data_addr_offset;
+	else
+		plat_priv->hang_data_addr_offset = 0;
+
+	if (resp->hwid_bitmap_valid)
+		plat_priv->hwid_bitmap = resp->hwid_bitmap;
+
+	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;
+		}
+	}
+
+	if (resp->serial_id_valid) {
+		plat_priv->serial_id = resp->serial_id;
+		cnss_pr_info("serial id  0x%x 0x%x\n",
+			     resp->serial_id.serial_id_msb,
+			     resp->serial_id.serial_id_lsb);
+	}
+
+	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,
+		    plat_priv->board_info.board_id, plat_priv->soc_info.soc_id,
+		    plat_priv->otp_version);
+	cnss_pr_dbg("fw_version: 0x%x, fw_build_timestamp: %s, fw_build_id: %s, hwid_bitmap:0x%x\n",
+		    plat_priv->fw_version_info.fw_version,
+		    plat_priv->fw_version_info.fw_build_timestamp,
+		    plat_priv->fw_build_id,
+		    plat_priv->hwid_bitmap);
+	cnss_pr_dbg("Hang event params, Length: 0x%x, Offset Address: 0x%x\n",
+		    plat_priv->hang_event_data_len,
+		    plat_priv->hang_data_addr_offset);
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	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)
+{
+	char filename_tmp[MAX_FIRMWARE_NAME_LEN];
+	int ret = 0;
+
+	switch (bdf_type) {
+	case CNSS_BDF_ELF:
+		/* Board ID will be equal or less than 0xFF in GF mask case */
+		if (plat_priv->board_info.board_id == 0xFF) {
+			if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK)
+				snprintf(filename_tmp, filename_len,
+					 ELF_BDF_FILE_NAME_GF);
+			else
+				snprintf(filename_tmp, filename_len,
+					 ELF_BDF_FILE_NAME);
+		} else if (plat_priv->board_info.board_id < 0xFF) {
+			if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK)
+				snprintf(filename_tmp, filename_len,
+					 ELF_BDF_FILE_NAME_GF_PREFIX "%02x",
+					 plat_priv->board_info.board_id);
+			else
+				snprintf(filename_tmp, filename_len,
+					 ELF_BDF_FILE_NAME_PREFIX "%02x",
+					 plat_priv->board_info.board_id);
+		} else {
+			snprintf(filename_tmp, filename_len,
+				 BDF_FILE_NAME_PREFIX "%02x.e%02x",
+				 plat_priv->board_info.board_id >> 8 & 0xFF,
+				 plat_priv->board_info.board_id & 0xFF);
+		}
+		break;
+	case CNSS_BDF_BIN:
+		if (plat_priv->board_info.board_id == 0xFF) {
+			if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK)
+				snprintf(filename_tmp, filename_len,
+					 BIN_BDF_FILE_NAME_GF);
+			else
+				snprintf(filename_tmp, filename_len,
+					 BIN_BDF_FILE_NAME);
+		} else if (plat_priv->board_info.board_id < 0xFF) {
+			if (plat_priv->chip_info.chip_id & CHIP_ID_GF_MASK)
+				snprintf(filename_tmp, filename_len,
+					 BIN_BDF_FILE_NAME_GF_PREFIX "%02x",
+					 plat_priv->board_info.board_id);
+			else
+				snprintf(filename_tmp, filename_len,
+					 BIN_BDF_FILE_NAME_PREFIX "%02x",
+					 plat_priv->board_info.board_id);
+		} else {
+			snprintf(filename_tmp, filename_len,
+				 BDF_FILE_NAME_PREFIX "%02x.b%02x",
+				 plat_priv->board_info.board_id >> 8 & 0xFF,
+				 plat_priv->board_info.board_id & 0xFF);
+		}
+		break;
+	case CNSS_BDF_REGDB:
+		snprintf(filename_tmp, filename_len, REGDB_FILE_NAME);
+		break;
+	case CNSS_BDF_HDS:
+		snprintf(filename_tmp, filename_len, HDS_FILE_NAME);
+		break;
+	default:
+		cnss_pr_err("Invalid BDF type: %d\n",
+			    plat_priv->ctrl_params.bdf_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret)
+		cnss_bus_add_fw_prefix_name(plat_priv, filename, filename_tmp);
+
+	return ret;
+}
+
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				 u32 bdf_type)
+{
+	struct wlfw_bdf_download_req_msg_v01 *req;
+	struct wlfw_bdf_download_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	char filename[MAX_FIRMWARE_NAME_LEN];
+	const struct firmware *fw_entry = NULL;
+	const u8 *temp;
+	unsigned int remaining;
+	int ret = 0;
+
+	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)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	ret = cnss_get_bdf_file_name(plat_priv, bdf_type,
+				     filename, sizeof(filename));
+	if (ret)
+		goto err_req_fw;
+
+	cnss_pr_dbg("Invoke firmware_request_nowarn for %s\n", filename);
+	if (bdf_type == CNSS_BDF_REGDB)
+		ret = cnss_request_firmware_direct(plat_priv, &fw_entry,
+						   filename);
+	else
+		ret = firmware_request_nowarn(&fw_entry, filename,
+					      &plat_priv->plat_dev->dev);
+
+	if (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 %s: %s, size: %u\n",
+		    cnss_bdf_type_to_str(bdf_type), filename, remaining);
+
+	while (remaining) {
+		req->valid = 1;
+		req->file_id_valid = 1;
+		req->file_id = plat_priv->board_info.board_id;
+		req->total_size_valid = 1;
+		req->total_size = remaining;
+		req->seg_id_valid = 1;
+		req->data_valid = 1;
+		req->end_valid = 1;
+		req->bdf_type_valid = 1;
+		req->bdf_type = bdf_type;
+
+		if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+			req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+		} else {
+			req->data_len = remaining;
+			req->end = 1;
+		}
+
+		memcpy(req->data, temp, req->data_len);
+
+		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 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_send_request
+			(&plat_priv->qmi_wlfw, NULL, &txn,
+			 QMI_WLFW_BDF_DOWNLOAD_REQ_V01,
+			 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
+			 wlfw_bdf_download_req_msg_v01_ei, req);
+		if (ret < 0) {
+			qmi_txn_cancel(&txn);
+			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("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("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;
+		}
+
+		remaining -= req->data_len;
+		temp += req->data_len;
+		req->seg_id++;
+	}
+
+	release_firmware(fw_entry);
+
+	if (resp->host_bdf_data_valid) {
+		/* QCA6490 enable S3E regulator for IPA configuration only */
+		if (!(resp->host_bdf_data & QMI_WLFW_HW_XPA_V01))
+			cnss_enable_int_pow_amp_vreg(plat_priv);
+
+		plat_priv->cbc_file_download =
+			resp->host_bdf_data & QMI_WLFW_CBC_FILE_DOWNLOAD_V01;
+		cnss_pr_info("Host BDF config: HW_XPA: %d CalDB: %d\n",
+			     resp->host_bdf_data & QMI_WLFW_HW_XPA_V01,
+			     plat_priv->cbc_file_download);
+	}
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+err_send:
+	release_firmware(fw_entry);
+err_req_fw:
+	if (!(bdf_type == CNSS_BDF_REGDB ||
+	      test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state) ||
+	      ret == -EAGAIN))
+		CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_tme_patch_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file)
+{
+	struct wlfw_tme_lite_info_req_msg_v01 *req;
+	struct wlfw_tme_lite_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *tme_lite_mem = &plat_priv->tme_lite_mem;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending TME patch information message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	if (plat_priv->device_id != PEACH_DEVICE_ID)
+		return 0;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	if (!tme_lite_mem->pa || !tme_lite_mem->size) {
+		cnss_pr_err("Memory for TME patch is not available\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("TME-L patch memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    tme_lite_mem->va, &tme_lite_mem->pa, tme_lite_mem->size);
+
+	req->tme_file = file;
+	req->addr = plat_priv->tme_lite_mem.pa;
+	req->size = plat_priv->tme_lite_mem.size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_tme_lite_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for TME patch information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_TME_LITE_INFO_REQ_V01,
+			       WLFW_TME_LITE_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_tme_lite_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send TME patch information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of TME patch information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("TME patch information request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file)
+{
+	struct wlfw_tme_lite_info_req_msg_v01 *req;
+	struct wlfw_tme_lite_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *tme_opt_file_mem = NULL;
+	char *file_name = NULL;
+	int ret = 0;
+
+	if (plat_priv->device_id != PEACH_DEVICE_ID)
+		return 0;
+
+	cnss_pr_dbg("Sending TME opt file information message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	if (file == WLFW_TME_LITE_OEM_FUSE_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[0];
+		file_name = TME_OEM_FUSE_FILE_NAME;
+	} else if (file == WLFW_TME_LITE_RPR_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[1];
+		file_name = TME_RPR_FILE_NAME;
+	} else if (file == WLFW_TME_LITE_DPR_FILE_V01) {
+		tme_opt_file_mem = &plat_priv->tme_opt_file_mem[2];
+		file_name = TME_DPR_FILE_NAME;
+	}
+
+	if (!tme_opt_file_mem || !tme_opt_file_mem->pa ||
+	    !tme_opt_file_mem->size) {
+		cnss_pr_err("Memory for TME opt file is not available\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("TME opt file %s memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    file_name, tme_opt_file_mem->va, &tme_opt_file_mem->pa, tme_opt_file_mem->size);
+
+	req->tme_file = file;
+	req->addr = tme_opt_file_mem->pa;
+	req->size = tme_opt_file_mem->size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_tme_lite_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_TME_LITE_INFO_REQ_V01,
+			       WLFW_TME_LITE_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_tme_lite_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of TME opt file information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		ret = -resp->resp.result;
+		if (resp->resp.error == QMI_ERR_HARDWARE_RESTRICTED_V01) {
+			cnss_pr_err("TME Power On failed\n");
+			goto out;
+		} else if (resp->resp.error == QMI_ERR_ENOMEM_V01) {
+			cnss_pr_err("malloc SRAM failed\n");
+			goto out;
+		}
+		cnss_pr_err("TME opt file information request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_m3_info_req_msg_v01 *req;
+	struct wlfw_m3_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending M3 information message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	if (!m3_mem->pa || !m3_mem->size) {
+		cnss_pr_err("Memory for M3 is not available\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("M3 memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    m3_mem->va, &m3_mem->pa, m3_mem->size);
+
+	req->addr = plat_priv->m3_mem.pa;
+	req->size = plat_priv->m3_mem.size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_m3_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for M3 information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_M3_INFO_REQ_V01,
+			       WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_m3_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send M3 information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of M3 information request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("M3 information request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_aux_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_aux_uc_info_req_msg_v01 *req;
+	struct wlfw_aux_uc_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *aux_mem = &plat_priv->aux_mem;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending QMI_WLFW_AUX_UC_INFO_REQ_V01 message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	if (!aux_mem->pa || !aux_mem->size) {
+		cnss_pr_err("Memory for AUX is not available\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("AUX memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    aux_mem->va, &aux_mem->pa, aux_mem->size);
+
+	req->addr = plat_priv->aux_mem.pa;
+	req->size = plat_priv->aux_mem.size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_aux_uc_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for QMI_WLFW_AUX_UC_INFO_REQ_V01 request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_AUX_UC_INFO_REQ_V01,
+			       WLFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_aux_uc_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send QMI_WLFW_AUX_UC_INFO_REQ_V01 request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of QMI_WLFW_AUX_UC_INFO_REQ_V01 request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("QMI_WLFW_AUX_UC_INFO_REQ_V01 request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_wlan_mac_req_send_sync(struct cnss_plat_data *plat_priv,
+				     u8 *mac, u32 mac_len)
+{
+	struct wlfw_mac_addr_req_msg_v01 req;
+	struct wlfw_mac_addr_resp_msg_v01 resp = {0};
+	struct qmi_txn txn;
+	int ret;
+
+	if (!plat_priv || !mac || mac_len != QMI_WLFW_MAC_ADDR_SIZE_V01)
+		return -EINVAL;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_mac_addr_resp_msg_v01_ei, &resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for mac req, err: %d\n",
+			    ret);
+		ret = -EIO;
+		goto out;
+	}
+
+		cnss_pr_dbg("Sending WLAN mac req [%pM], state: 0x%lx\n",
+			    mac, plat_priv->driver_state);
+	memcpy(req.mac_addr, mac, mac_len);
+	req.mac_addr_valid = 1;
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_MAC_ADDR_REQ_V01,
+			       WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_mac_addr_req_msg_v01_ei, &req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send mac req, err: %d\n", ret);
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for resp of mac req, err: %d\n",
+			    ret);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("WLAN mac req failed, result: %d, err: %d\n",
+			    resp.resp.result);
+		ret = -resp.resp.result;
+	}
+out:
+	return ret;
+}
+
+int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_name,
+				  u32 total_size)
+{
+	int ret = 0;
+	struct wlfw_qdss_trace_data_req_msg_v01 *req;
+	struct wlfw_qdss_trace_data_resp_msg_v01 *resp;
+	unsigned char *p_qdss_trace_data_temp, *p_qdss_trace_data = NULL;
+	unsigned int remaining;
+	struct qmi_txn txn;
+
+	cnss_pr_dbg("%s\n", __func__);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	p_qdss_trace_data = kzalloc(total_size, GFP_KERNEL);
+	if (!p_qdss_trace_data) {
+		ret = ENOMEM;
+		goto end;
+	}
+
+	remaining = total_size;
+	p_qdss_trace_data_temp = p_qdss_trace_data;
+	while (remaining && resp->end == 0) {
+		ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+				   wlfw_qdss_trace_data_resp_msg_v01_ei, resp);
+
+		if (ret < 0) {
+			cnss_pr_err("Fail to init txn for QDSS trace resp %d\n",
+				    ret);
+			goto fail;
+		}
+
+		ret = qmi_send_request
+			(&plat_priv->qmi_wlfw, NULL, &txn,
+			 QMI_WLFW_QDSS_TRACE_DATA_REQ_V01,
+			 WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN,
+			 wlfw_qdss_trace_data_req_msg_v01_ei, req);
+
+		if (ret < 0) {
+			qmi_txn_cancel(&txn);
+			cnss_pr_err("Fail to send QDSS trace data req %d\n",
+				    ret);
+			goto fail;
+		}
+
+		ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout);
+
+		if (ret < 0) {
+			cnss_pr_err("QDSS trace resp wait failed with rc %d\n",
+				    ret);
+			goto fail;
+		} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+			cnss_pr_err("QMI QDSS trace request rejected, result:%d error:%d\n",
+				    resp->resp.result, resp->resp.error);
+			ret = -resp->resp.result;
+			goto fail;
+		} else {
+			ret = 0;
+		}
+
+		cnss_pr_dbg("%s: response total size  %d data len %d",
+			    __func__, resp->total_size, resp->data_len);
+
+		if ((resp->total_size_valid == 1 &&
+		     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 <= remaining) {
+			memcpy(p_qdss_trace_data_temp,
+			       resp->data, resp->data_len);
+		} else {
+			cnss_pr_err("%s: Unmatched qdss trace data, Expect total_size %u, seg_id %u, Recv total_size_valid %u, total_size %u, seg_id_valid %u, seg_id %u, data_len_valid %u, data_len %u",
+				    __func__,
+				     total_size, req->seg_id,
+				     resp->total_size_valid,
+				     resp->total_size,
+				     resp->seg_id_valid,
+				     resp->seg_id,
+				     resp->data_valid,
+				     resp->data_len);
+			ret = -1;
+			goto fail;
+		}
+
+		remaining -= resp->data_len;
+		p_qdss_trace_data_temp += resp->data_len;
+		req->seg_id++;
+	}
+
+	if (remaining == 0 && (resp->end_valid && resp->end)) {
+		ret = cnss_genl_send_msg(p_qdss_trace_data,
+					 CNSS_GENL_MSG_TYPE_QDSS, file_name,
+					 total_size);
+		if (ret < 0) {
+			cnss_pr_err("Fail to save QDSS trace data: %d\n",
+				    ret);
+		ret = -1;
+		goto fail;
+		}
+	} else {
+		cnss_pr_err("%s: QDSS trace file corrupted: remaining %u, end_valid %u, end %u",
+			    __func__,
+			     remaining, resp->end_valid, resp->end);
+		ret = -1;
+		goto fail;
+	}
+
+fail:
+	kfree(p_qdss_trace_data);
+
+end:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+static void cnss_get_qdss_cfg_filename(struct cnss_plat_data *plat_priv,
+				       char *filename, u32 filename_len,
+				       bool fallback_file)
+{
+	char filename_tmp[MAX_FIRMWARE_NAME_LEN];
+	char *build_str = QDSS_FILE_BUILD_STR;
+
+	if (fallback_file)
+		build_str = "";
+
+	if (plat_priv->device_version.major_version == FW_V2_NUMBER)
+		snprintf(filename_tmp, filename_len, QDSS_TRACE_CONFIG_FILE
+			 "_%s%s.cfg", build_str, HW_V2_NUMBER);
+	else
+		snprintf(filename_tmp, filename_len, QDSS_TRACE_CONFIG_FILE
+			 "_%s%s.cfg", build_str, HW_V1_NUMBER);
+
+	cnss_bus_add_fw_prefix_name(plat_priv, filename, filename_tmp);
+}
+
+int cnss_wlfw_qdss_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_qdss_trace_config_download_req_msg_v01 *req;
+	struct wlfw_qdss_trace_config_download_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	const struct firmware *fw_entry = NULL;
+	const u8 *temp;
+	char qdss_cfg_filename[MAX_FIRMWARE_NAME_LEN];
+	unsigned int remaining;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending QDSS config download message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	cnss_get_qdss_cfg_filename(plat_priv, qdss_cfg_filename,
+				   sizeof(qdss_cfg_filename), false);
+
+	cnss_pr_dbg("Invoke firmware_request_nowarn for %s\n",
+		    qdss_cfg_filename);
+	ret = cnss_request_firmware_direct(plat_priv, &fw_entry,
+					   qdss_cfg_filename);
+	if (ret) {
+		cnss_pr_dbg("Unable to load %s ret %d, try default file\n",
+			    qdss_cfg_filename, ret);
+		cnss_get_qdss_cfg_filename(plat_priv, qdss_cfg_filename,
+					   sizeof(qdss_cfg_filename),
+					   true);
+		cnss_pr_dbg("Invoke firmware_request_nowarn for %s\n",
+			    qdss_cfg_filename);
+		ret = cnss_request_firmware_direct(plat_priv, &fw_entry,
+						   qdss_cfg_filename);
+		if (ret) {
+			cnss_pr_err("Unable to load %s ret %d\n",
+				    qdss_cfg_filename, ret);
+			goto err_req_fw;
+		}
+	}
+
+	temp = fw_entry->data;
+	remaining = fw_entry->size;
+
+	cnss_pr_dbg("Downloading QDSS: %s, size: %u\n",
+		    qdss_cfg_filename, remaining);
+
+	while (remaining) {
+		req->total_size_valid = 1;
+		req->total_size = remaining;
+		req->seg_id_valid = 1;
+		req->data_valid = 1;
+		req->end_valid = 1;
+
+		if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+			req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+		} else {
+			req->data_len = remaining;
+			req->end = 1;
+		}
+
+		memcpy(req->data, temp, req->data_len);
+
+		ret = qmi_txn_init
+			(&plat_priv->qmi_wlfw, &txn,
+			 wlfw_qdss_trace_config_download_resp_msg_v01_ei,
+			 resp);
+		if (ret < 0) {
+			cnss_pr_err("Failed to initialize txn for QDSS download request, err: %d\n",
+				    ret);
+			goto err_send;
+		}
+
+		ret = qmi_send_request
+		      (&plat_priv->qmi_wlfw, NULL, &txn,
+		       QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01,
+		       WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
+		       wlfw_qdss_trace_config_download_req_msg_v01_ei, req);
+		if (ret < 0) {
+			qmi_txn_cancel(&txn);
+			cnss_pr_err("Failed to send respond QDSS download request, err: %d\n",
+				    ret);
+			goto err_send;
+		}
+
+		ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout);
+		if (ret < 0) {
+			cnss_pr_err("Failed to wait for response of QDSS download request, err: %d\n",
+				    ret);
+			goto err_send;
+		}
+
+		if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+			cnss_pr_err("QDSS download request failed, result: %d, err: %d\n",
+				    resp->resp.result, resp->resp.error);
+			ret = -resp->resp.result;
+			goto err_send;
+		}
+
+		remaining -= req->data_len;
+		temp += req->data_len;
+		req->seg_id++;
+	}
+
+	release_firmware(fw_entry);
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+err_send:
+	release_firmware(fw_entry);
+err_req_fw:
+
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+static int wlfw_send_qdss_trace_mode_req
+		(struct cnss_plat_data *plat_priv,
+		 enum wlfw_qdss_trace_mode_enum_v01 mode,
+		 unsigned long long option)
+{
+	int rc = 0;
+	int tmp = 0;
+	struct wlfw_qdss_trace_mode_req_msg_v01 *req;
+	struct wlfw_qdss_trace_mode_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->mode_valid = 1;
+	req->mode = mode;
+	req->option_valid = 1;
+	req->option = option;
+
+	tmp = plat_priv->hw_trc_override;
+
+	req->hw_trc_disable_override_valid = 1;
+	req->hw_trc_disable_override =
+	(tmp > QMI_PARAM_DISABLE_V01 ? QMI_PARAM_DISABLE_V01 :
+		 (tmp < 0 ? QMI_PARAM_INVALID_V01 : tmp));
+
+	cnss_pr_dbg("%s: mode %u, option %llu, hw_trc_disable_override: %u",
+		    __func__, mode, option, req->hw_trc_disable_override);
+
+	rc = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			  wlfw_qdss_trace_mode_resp_msg_v01_ei, resp);
+	if (rc < 0) {
+		cnss_pr_err("Fail to init txn for QDSS Mode resp %d\n",
+			    rc);
+		goto out;
+	}
+
+	rc = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			      QMI_WLFW_QDSS_TRACE_MODE_REQ_V01,
+			      WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN,
+			      wlfw_qdss_trace_mode_req_msg_v01_ei, req);
+	if (rc < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Fail to send QDSS Mode req %d\n", rc);
+		goto out;
+	}
+
+	rc = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout);
+	if (rc < 0) {
+		cnss_pr_err("QDSS Mode resp wait failed with rc %d\n",
+			    rc);
+		goto out;
+	} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("QMI QDSS Mode request rejected, result:%d error:%d\n",
+			    resp->resp.result, resp->resp.error);
+		rc = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(resp);
+	kfree(req);
+	return rc;
+out:
+	kfree(resp);
+	kfree(req);
+	CNSS_QMI_ASSERT();
+	return rc;
+}
+
+int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv)
+{
+	return wlfw_send_qdss_trace_mode_req(plat_priv,
+					     QMI_WLFW_QDSS_TRACE_ON_V01, 0);
+}
+
+int wlfw_qdss_trace_stop(struct cnss_plat_data *plat_priv, unsigned long long option)
+{
+	return wlfw_send_qdss_trace_mode_req(plat_priv, QMI_WLFW_QDSS_TRACE_OFF_V01,
+					     option);
+}
+
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+				  enum cnss_driver_mode mode)
+{
+	struct wlfw_wlan_mode_req_msg_v01 *req;
+	struct wlfw_wlan_mode_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
+		    cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);
+
+	if (mode == CNSS_OFF &&
+	    test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Recovery is in progress, ignore mode off request\n");
+		return 0;
+	}
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->mode = (enum wlfw_driver_mode_enum_v01)mode;
+	req->hw_debug_valid = 1;
+	req->hw_debug = 0;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_wlan_mode_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for mode request, mode: %s(%d), err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_WLAN_MODE_REQ_V01,
+			       WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_wlan_mode_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of mode request, mode: %s(%d), err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, resp->resp.result,
+			    resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	if (mode == CNSS_OFF) {
+		cnss_pr_dbg("WLFW service is disconnected while sending mode off request\n");
+		ret = 0;
+	} else {
+		CNSS_QMI_ASSERT();
+	}
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+				 struct cnss_wlan_enable_cfg *config,
+				 const char *host_version)
+{
+	struct wlfw_wlan_cfg_req_msg_v01 *req;
+	struct wlfw_wlan_cfg_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	u32 i, ce_id, num_vectors, user_base_data, base_vector;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->host_version_valid = 1;
+	strlcpy(req->host_version, host_version,
+		QMI_WLFW_MAX_STR_LEN_V01 + 1);
+
+	req->tgt_cfg_valid = 1;
+	if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
+		req->tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
+	else
+		req->tgt_cfg_len = config->num_ce_tgt_cfg;
+	for (i = 0; i < req->tgt_cfg_len; i++) {
+		req->tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
+		req->tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
+		req->tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
+		req->tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
+		req->tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
+	}
+
+	req->svc_cfg_valid = 1;
+	if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
+		req->svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
+	else
+		req->svc_cfg_len = config->num_ce_svc_pipe_cfg;
+	for (i = 0; i < req->svc_cfg_len; i++) {
+		req->svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
+		req->svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
+		req->svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
+	}
+
+	if (plat_priv->device_id != KIWI_DEVICE_ID &&
+	    plat_priv->device_id != MANGO_DEVICE_ID &&
+	    plat_priv->device_id != PEACH_DEVICE_ID) {
+		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;
+
+			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 >
+		    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;
+
+		plat_priv->num_shadow_regs_v3 = req->shadow_reg_v3_len;
+
+		cnss_pr_dbg("Shadow reg v3 len: %d\n",
+			    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);
+	}
+
+	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,
+			   wlfw_wlan_cfg_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for WLAN config request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_WLAN_CFG_REQ_V01,
+			       WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_wlan_cfg_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send WLAN config request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of WLAN config request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("WLAN config request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+				     u32 offset, u32 mem_type,
+				     u32 data_len, u8 *data)
+{
+	struct wlfw_athdiag_read_req_msg_v01 *req;
+	struct wlfw_athdiag_read_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+		cnss_pr_err("Invalid parameters for athdiag read: data %pK, data_len %u\n",
+			    data, data_len);
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("athdiag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n",
+		    plat_priv->driver_state, offset, mem_type, data_len);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->offset = offset;
+	req->mem_type = mem_type;
+	req->data_len = data_len;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_athdiag_read_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for athdiag read request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_ATHDIAG_READ_REQ_V01,
+			       WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_athdiag_read_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send athdiag read request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of athdiag read request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Athdiag read request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	if (!resp->data_valid || resp->data_len != data_len) {
+		cnss_pr_err("athdiag read data is invalid, data_valid = %u, data_len = %u\n",
+			    resp->data_valid, resp->data_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	memcpy(data, resp->data, resp->data_len);
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+				      u32 offset, u32 mem_type,
+				      u32 data_len, u8 *data)
+{
+	struct wlfw_athdiag_write_req_msg_v01 *req;
+	struct wlfw_athdiag_write_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+		cnss_pr_err("Invalid parameters for athdiag write: data %pK, data_len %u\n",
+			    data, data_len);
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %pK\n",
+		    plat_priv->driver_state, offset, mem_type, data_len, data);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->offset = offset;
+	req->mem_type = mem_type;
+	req->data_len = data_len;
+	memcpy(req->data, data, data_len);
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_athdiag_write_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for athdiag write request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_ATHDIAG_WRITE_REQ_V01,
+			       WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_athdiag_write_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send athdiag write request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of athdiag write request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Athdiag write request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+			    u8 fw_log_mode)
+{
+	struct wlfw_ini_req_msg_v01 *req;
+	struct wlfw_ini_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n",
+		    plat_priv->driver_state, fw_log_mode);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->enablefwlog_valid = 1;
+	req->enablefwlog = fw_log_mode;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_ini_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for ini request, fw_log_mode: %d, err: %d\n",
+			    fw_log_mode, ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_INI_REQ_V01,
+			       WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_ini_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send ini request, fw_log_mode: %d, err: %d\n",
+			    fw_log_mode, ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of ini request, fw_log_mode: %d, err: %d\n",
+			    fw_log_mode, ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Ini request failed, fw_log_mode: %d, result: %d, err: %d\n",
+			    fw_log_mode, resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_pcie_gen_switch_req_msg_v01 req;
+	struct wlfw_pcie_gen_switch_resp_msg_v01 resp = {0};
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (plat_priv->pcie_gen_speed == QMI_PCIE_GEN_SPEED_INVALID_V01 ||
+	    !plat_priv->fw_pcie_gen_switch) {
+		cnss_pr_dbg("PCIE Gen speed not setup\n");
+		return 0;
+	}
+
+	cnss_pr_dbg("Sending PCIE Gen speed: %d state: 0x%lx\n",
+		    plat_priv->pcie_gen_speed, plat_priv->driver_state);
+	req.pcie_speed = (enum wlfw_pcie_gen_speed_v01)
+			plat_priv->pcie_gen_speed;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_pcie_gen_switch_resp_msg_v01_ei, &resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for PCIE speed switch err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_PCIE_GEN_SWITCH_REQ_V01,
+			       WLFW_PCIE_GEN_SWITCH_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_pcie_gen_switch_req_msg_v01_ei, &req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send PCIE speed switch, err: %d\n", ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for PCIE Gen switch resp, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("PCIE Gen Switch req failed, Speed: %d, result: %d, err: %d\n",
+			    plat_priv->pcie_gen_speed, resp.resp.result,
+			    resp.resp.error);
+		ret = -resp.resp.result;
+	}
+out:
+	/* Reset PCIE Gen speed after one time use */
+	plat_priv->pcie_gen_speed = QMI_PCIE_GEN_SPEED_INVALID_V01;
+	return ret;
+}
+
+int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_antenna_switch_req_msg_v01 *req;
+	struct wlfw_antenna_switch_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending antenna switch sync request, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_antenna_switch_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for antenna switch request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_ANTENNA_SWITCH_REQ_V01,
+			       WLFW_ANTENNA_SWITCH_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_antenna_switch_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send antenna switch request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of antenna switch request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_dbg("Antenna switch request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	if (resp->antenna_valid)
+		plat_priv->antenna = resp->antenna;
+
+	cnss_pr_dbg("Antenna valid: %u, antenna 0x%llx\n",
+		    resp->antenna_valid, resp->antenna);
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_antenna_grant_req_msg_v01 *req;
+	struct wlfw_antenna_grant_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending antenna grant sync request, state: 0x%lx, grant 0x%llx\n",
+		    plat_priv->driver_state, plat_priv->grant);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->grant_valid = 1;
+	req->grant = plat_priv->grant;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_antenna_grant_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for antenna grant request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_ANTENNA_GRANT_REQ_V01,
+			       WLFW_ANTENNA_GRANT_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_antenna_grant_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send antenna grant request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of antenna grant request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Antenna grant request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_qdss_trace_mem_info_req_msg_v01 *req;
+	struct wlfw_qdss_trace_mem_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	struct cnss_fw_mem *qdss_mem = plat_priv->qdss_mem;
+	int ret = 0;
+	int i;
+
+	cnss_pr_dbg("Sending QDSS trace mem info, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		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",
+			    qdss_mem[i].va, &qdss_mem[i].pa,
+			    qdss_mem[i].size, qdss_mem[i].type);
+
+		req->mem_seg[i].addr = qdss_mem[i].pa;
+		req->mem_seg[i].size = qdss_mem[i].size;
+		req->mem_seg[i].type = qdss_mem[i].type;
+	}
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_qdss_trace_mem_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Fail to initialize txn for QDSS trace mem request: err %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01,
+			       WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_qdss_trace_mem_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Fail to send QDSS trace mem info request: err %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Fail to wait for response of QDSS trace mem info request, err %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("QDSS trace mem info request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv,
+					struct cnss_wfc_cfg cfg)
+{
+	struct wlfw_wfc_call_status_req_msg_v01 *req;
+	struct wlfw_wfc_call_status_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Drop host WFC indication as FW not initialized\n");
+		return -EINVAL;
+	}
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->wfc_call_active_valid = 1;
+	req->wfc_call_active = cfg.mode;
+
+	cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_wfc_call_status_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n",
+			    ret);
+		goto out;
+	}
+
+	cnss_pr_dbg("Send WFC Mode: %d\n", cfg.mode);
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_WFC_CALL_STATUS_REQ_V01,
+			       WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_wfc_call_status_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = 0;
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+
+}
+static int cnss_wlfw_wfc_call_status_send_sync
+	(struct cnss_plat_data *plat_priv,
+	 const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg)
+{
+	struct wlfw_wfc_call_status_req_msg_v01 *req;
+	struct wlfw_wfc_call_status_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Drop IMS WFC indication as FW not initialized\n");
+		return -EINVAL;
+	}
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	/**
+	 * WFC Call r1 design has CNSS as pass thru using opaque hex buffer.
+	 * But in r2 update QMI structure is expanded and as an effect qmi
+	 * decoded structures have padding. Thus we cannot use buffer design.
+	 * For backward compatibility for r1 design copy only wfc_call_active
+	 * value in hex buffer.
+	 */
+	req->wfc_call_status_len = sizeof(ind_msg->wfc_call_active);
+	req->wfc_call_status[0] = ind_msg->wfc_call_active;
+
+	/* wfc_call_active is mandatory in IMS indication */
+	req->wfc_call_active_valid = 1;
+	req->wfc_call_active = ind_msg->wfc_call_active;
+	req->all_wfc_calls_held_valid = ind_msg->all_wfc_calls_held_valid;
+	req->all_wfc_calls_held = ind_msg->all_wfc_calls_held;
+	req->is_wfc_emergency_valid = ind_msg->is_wfc_emergency_valid;
+	req->is_wfc_emergency = ind_msg->is_wfc_emergency;
+	req->twt_ims_start_valid = ind_msg->twt_ims_start_valid;
+	req->twt_ims_start = ind_msg->twt_ims_start;
+	req->twt_ims_int_valid = ind_msg->twt_ims_int_valid;
+	req->twt_ims_int = ind_msg->twt_ims_int;
+	req->media_quality_valid = ind_msg->media_quality_valid;
+	req->media_quality =
+		(enum wlfw_wfc_media_quality_v01)ind_msg->media_quality;
+
+	cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_wfc_call_status_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_WFC_CALL_STATUS_REQ_V01,
+			       WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_wfc_call_status_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+	ret = 0;
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_dynamic_feature_mask_req_msg_v01 *req;
+	struct wlfw_dynamic_feature_mask_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending dynamic feature mask 0x%llx, state: 0x%lx\n",
+		    plat_priv->dynamic_feature,
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->mask_valid = 1;
+	req->mask = plat_priv->dynamic_feature;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_dynamic_feature_mask_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Fail to initialize txn for dynamic feature mask request: err %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request
+		(&plat_priv->qmi_wlfw, NULL, &txn,
+		 QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01,
+		 WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN,
+		 wlfw_dynamic_feature_mask_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Fail to send dynamic feature mask request: err %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Fail to wait for response of dynamic feature mask request, err %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Dynamic feature mask request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_get_info_send_sync(struct cnss_plat_data *plat_priv, int type,
+				 void *cmd, int cmd_len)
+{
+	struct wlfw_get_info_req_msg_v01 *req;
+	struct wlfw_get_info_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	cnss_pr_buf("Sending get info message, type: %d, cmd length: %d, state: 0x%lx\n",
+		    type, cmd_len, plat_priv->driver_state);
+
+	if (cmd_len > QMI_WLFW_MAX_DATA_SIZE_V01)
+		return -EINVAL;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->type = type;
+	req->data_len = cmd_len;
+	memcpy(req->data, cmd, req->data_len);
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_get_info_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for get info request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_GET_INFO_REQ_V01,
+			       WLFW_GET_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_get_info_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send get info request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of get info request, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Get info request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	kfree(req);
+	kfree(resp);
+	return 0;
+
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv)
+{
+	return QMI_WLFW_TIMEOUT_MS;
+}
+
+static void cnss_wlfw_request_mem_ind_cb(struct qmi_handle *qmi_wlfw,
+					 struct sockaddr_qrtr *sq,
+					 struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_request_mem_ind_msg_v01 *ind_msg = data;
+	int i;
+
+	cnss_pr_dbg("Received QMI WLFW request memory indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		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",
+			    ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type);
+		plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
+		plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
+		if (!plat_priv->fw_mem[i].va &&
+		    plat_priv->fw_mem[i].type == CNSS_MEM_TYPE_DDR)
+			plat_priv->fw_mem[i].attrs |=
+				DMA_ATTR_FORCE_CONTIGUOUS;
+		if (plat_priv->fw_mem[i].type == CNSS_MEM_CAL_V01)
+			plat_priv->cal_mem = &plat_priv->fw_mem[i];
+	}
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
+			       0, NULL);
+}
+
+static void cnss_wlfw_fw_mem_ready_ind_cb(struct qmi_handle *qmi_wlfw,
+					  struct sockaddr_qrtr *sq,
+					  struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+
+	cnss_pr_dbg("Received QMI WLFW FW memory ready indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_MEM_READY,
+			       0, NULL);
+}
+
+/**
+ * cnss_wlfw_fw_ready_ind_cb: FW ready indication handler (Helium arch)
+ *
+ * This event is not required for HST/ HSP as FW calibration done is
+ * provided in QMI_WLFW_CAL_DONE_IND_V01
+ */
+static void cnss_wlfw_fw_ready_ind_cb(struct qmi_handle *qmi_wlfw,
+				      struct sockaddr_qrtr *sq,
+				      struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	struct cnss_cal_info *cal_info;
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	if (plat_priv->device_id == QCA6390_DEVICE_ID ||
+	    plat_priv->device_id == QCA6490_DEVICE_ID) {
+		cnss_pr_dbg("Ignore FW Ready Indication for HST/HSP");
+		return;
+	}
+
+	cnss_pr_dbg("Received QMI WLFW FW ready indication.\n");
+	cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL);
+	if (!cal_info)
+		return;
+
+	cal_info->cal_status = CNSS_CAL_DONE;
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+			       0, cal_info);
+}
+
+static void cnss_wlfw_fw_init_done_ind_cb(struct qmi_handle *qmi_wlfw,
+					  struct sockaddr_qrtr *sq,
+					  struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+
+	cnss_pr_dbg("Received QMI WLFW FW initialization done indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_READY, 0, NULL);
+}
+
+static void cnss_wlfw_pin_result_ind_cb(struct qmi_handle *qmi_wlfw,
+					struct sockaddr_qrtr *sq,
+					struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_pin_connect_result_ind_msg_v01 *ind_msg = data;
+
+	cnss_pr_dbg("Received QMI WLFW pin connect result indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	if (ind_msg->pwr_pin_result_valid)
+		plat_priv->pin_result.fw_pwr_pin_result =
+		    ind_msg->pwr_pin_result;
+	if (ind_msg->phy_io_pin_result_valid)
+		plat_priv->pin_result.fw_phy_io_pin_result =
+		    ind_msg->phy_io_pin_result;
+	if (ind_msg->rf_pin_result_valid)
+		plat_priv->pin_result.fw_rf_pin_result = ind_msg->rf_pin_result;
+
+	cnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n",
+		    ind_msg->pwr_pin_result, ind_msg->phy_io_pin_result,
+		    ind_msg->rf_pin_result);
+}
+
+int cnss_wlfw_cal_report_req_send_sync(struct cnss_plat_data *plat_priv,
+				       u32 cal_file_download_size)
+{
+	struct wlfw_cal_report_req_msg_v01 req = {0};
+	struct wlfw_cal_report_resp_msg_v01 resp = {0};
+	struct qmi_txn txn;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending cal file report request. File size: %d, state: 0x%lx\n",
+		    cal_file_download_size, plat_priv->driver_state);
+	req.cal_file_download_size_valid = 1;
+	req.cal_file_download_size = cal_file_download_size;
+
+	ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn,
+			   wlfw_cal_report_resp_msg_v01_ei, &resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for Cal Report request, err: %d\n",
+			    ret);
+		goto out;
+	}
+	ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn,
+			       QMI_WLFW_CAL_REPORT_REQ_V01,
+			       WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN,
+			       wlfw_cal_report_req_msg_v01_ei, &req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send Cal Report request, err: %d\n",
+			    ret);
+		goto out;
+	}
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for response of Cal Report request, err: %d\n",
+			    ret);
+		goto out;
+	}
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Cal Report request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = -resp.resp.result;
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static void cnss_wlfw_cal_done_ind_cb(struct qmi_handle *qmi_wlfw,
+				      struct sockaddr_qrtr *sq,
+				      struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_cal_done_ind_msg_v01 *ind = data;
+	struct cnss_cal_info *cal_info;
+
+	cnss_pr_dbg("Received Cal done indication. File size: %d\n",
+		    ind->cal_file_upload_size);
+	cnss_pr_info("Calibration took %d ms\n",
+		     jiffies_to_msecs(jiffies - plat_priv->cal_time));
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+	if (ind->cal_file_upload_size_valid)
+		plat_priv->cal_file_size = ind->cal_file_upload_size;
+	cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL);
+	if (!cal_info)
+		return;
+
+	cal_info->cal_status = CNSS_CAL_DONE;
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+			       0, cal_info);
+}
+
+static void cnss_wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi_wlfw,
+						struct sockaddr_qrtr *sq,
+						struct qmi_txn *txn,
+						const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_qdss_trace_req_mem_ind_msg_v01 *ind_msg = data;
+	int i;
+
+	cnss_pr_dbg("Received QMI WLFW QDSS trace request mem indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	if (plat_priv->qdss_mem_seg_len) {
+		cnss_pr_err("Ignore double allocation for QDSS trace, current len %u\n",
+			    plat_priv->qdss_mem_seg_len);
+		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",
+			    ind_msg->mem_seg[i].size, ind_msg->mem_seg[i].type);
+		plat_priv->qdss_mem[i].type = ind_msg->mem_seg[i].type;
+		plat_priv->qdss_mem[i].size = ind_msg->mem_seg[i].size;
+	}
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
+			       0, NULL);
+}
+
+/**
+ * cnss_wlfw_fw_mem_file_save_ind_cb: Save given FW mem to filesystem
+ *
+ * QDSS_TRACE_SAVE_IND feature is overloaded to provide any host allocated
+ * fw memory segment for dumping to file system. Only one type of mem can be
+ * saved per indication and is provided in mem seg index 0.
+ *
+ * Return: None
+ */
+static void cnss_wlfw_fw_mem_file_save_ind_cb(struct qmi_handle *qmi_wlfw,
+					      struct sockaddr_qrtr *sq,
+					      struct qmi_txn *txn,
+					      const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_qdss_trace_save_ind_msg_v01 *ind_msg = data;
+	struct cnss_qmi_event_fw_mem_file_save_data *event_data;
+	int i = 0;
+
+	if (!txn || !data) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+	cnss_pr_dbg_buf("QMI fw_mem_file_save: source: %d  mem_seg: %d type: %u len: %u\n",
+			ind_msg->source, ind_msg->mem_seg_valid,
+			ind_msg->mem_seg[0].type, ind_msg->mem_seg_len);
+
+	event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+	if (!event_data)
+		return;
+
+	event_data->mem_type = ind_msg->mem_seg[0].type;
+	event_data->mem_seg_len = ind_msg->mem_seg_len;
+	event_data->total_size = ind_msg->total_size;
+
+	if (ind_msg->mem_seg_valid) {
+		if (ind_msg->mem_seg_len > QMI_WLFW_MAX_STR_LEN_V01) {
+			cnss_pr_err("Invalid seg len indication\n");
+			goto free_event_data;
+		}
+		for (i = 0; i < ind_msg->mem_seg_len; i++) {
+			event_data->mem_seg[i].addr = ind_msg->mem_seg[i].addr;
+			event_data->mem_seg[i].size = ind_msg->mem_seg[i].size;
+			if (event_data->mem_type != ind_msg->mem_seg[i].type) {
+				cnss_pr_err("FW Mem file save ind cannot have multiple mem types\n");
+				goto free_event_data;
+			}
+			cnss_pr_dbg_buf("seg-%d: addr 0x%llx size 0x%x\n",
+					i, ind_msg->mem_seg[i].addr,
+					ind_msg->mem_seg[i].size);
+		}
+	}
+
+	if (ind_msg->file_name_valid)
+		strlcpy(event_data->file_name, ind_msg->file_name,
+			QMI_WLFW_MAX_STR_LEN_V01 + 1);
+	if (ind_msg->source == 1) {
+		if (!ind_msg->file_name_valid)
+			strlcpy(event_data->file_name, "qdss_trace_wcss_etb",
+				QMI_WLFW_MAX_STR_LEN_V01 + 1);
+		cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA,
+				       0, event_data);
+	} else {
+		if (event_data->mem_type == QMI_WLFW_MEM_QDSS_V01) {
+			if (!ind_msg->file_name_valid)
+				strlcpy(event_data->file_name, "qdss_trace_ddr",
+					QMI_WLFW_MAX_STR_LEN_V01 + 1);
+		} else {
+			if (!ind_msg->file_name_valid)
+				strlcpy(event_data->file_name, "fw_mem_dump",
+					QMI_WLFW_MAX_STR_LEN_V01 + 1);
+		}
+
+		cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_MEM_FILE_SAVE,
+				       0, event_data);
+	}
+
+	return;
+
+free_event_data:
+	kfree(event_data);
+}
+
+static void cnss_wlfw_qdss_trace_free_ind_cb(struct qmi_handle *qmi_wlfw,
+					     struct sockaddr_qrtr *sq,
+					     struct qmi_txn *txn,
+					     const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
+			       0, NULL);
+}
+
+static void cnss_wlfw_respond_get_info_ind_cb(struct qmi_handle *qmi_wlfw,
+					      struct sockaddr_qrtr *sq,
+					      struct qmi_txn *txn,
+					      const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_respond_get_info_ind_msg_v01 *ind_msg = data;
+
+	cnss_pr_buf("Received QMI WLFW respond get info indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	cnss_pr_buf("Extract message with event length: %d, type: %d, is last: %d, seq no: %d\n",
+		    ind_msg->data_len, ind_msg->type,
+		    ind_msg->is_last, ind_msg->seq_no);
+
+	if (plat_priv->get_info_cb_ctx && plat_priv->get_info_cb)
+		plat_priv->get_info_cb(plat_priv->get_info_cb_ctx,
+				       (void *)ind_msg->data,
+				       ind_msg->data_len);
+}
+
+static void cnss_wlfw_driver_async_data_ind_cb(struct qmi_handle *qmi_wlfw,
+					       struct sockaddr_qrtr *sq,
+					       struct qmi_txn *txn,
+					       const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_driver_async_data_ind_msg_v01 *ind_msg = data;
+
+	cnss_pr_buf("Received QMI WLFW driver async data indication\n");
+
+	if (!txn) {
+		cnss_pr_err("Spurious indication\n");
+		return;
+	}
+
+	cnss_pr_buf("Extract message with event length: %d, type: %d\n",
+		    ind_msg->data_len, ind_msg->type);
+
+	if (plat_priv->get_driver_async_data_ctx &&
+			plat_priv->get_driver_async_data_cb)
+		plat_priv->get_driver_async_data_cb(
+			plat_priv->get_driver_async_data_ctx, ind_msg->type,
+			(void *)ind_msg->data, ind_msg->data_len);
+}
+
+
+static int cnss_ims_wfc_call_twt_cfg_send_sync
+	(struct cnss_plat_data *plat_priv,
+	 const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg)
+{
+	struct ims_private_service_wfc_call_twt_config_req_msg_v01 *req;
+	struct ims_private_service_wfc_call_twt_config_rsp_msg_v01 *resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if (!test_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_err("Drop FW WFC indication as IMS QMI not connected\n");
+		return -EINVAL;
+	}
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->twt_sta_start_valid = ind_msg->twt_sta_start_valid;
+	req->twt_sta_start = ind_msg->twt_sta_start;
+	req->twt_sta_int_valid = ind_msg->twt_sta_int_valid;
+	req->twt_sta_int = ind_msg->twt_sta_int;
+	req->twt_sta_upo_valid = ind_msg->twt_sta_upo_valid;
+	req->twt_sta_upo = ind_msg->twt_sta_upo;
+	req->twt_sta_sp_valid = ind_msg->twt_sta_sp_valid;
+	req->twt_sta_sp = ind_msg->twt_sta_sp;
+	req->twt_sta_dl_valid = req->twt_sta_dl_valid;
+	req->twt_sta_dl = req->twt_sta_dl;
+	req->twt_sta_config_changed_valid =
+				ind_msg->twt_sta_config_changed_valid;
+	req->twt_sta_config_changed = ind_msg->twt_sta_config_changed;
+
+	cnss_pr_dbg("CNSS->IMS: TWT_CFG_REQ: state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	ret =
+	qmi_txn_init(&plat_priv->ims_qmi, &txn,
+		     ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei,
+		     resp);
+	if (ret < 0) {
+		cnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Txn Init Err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret =
+	qmi_send_request(&plat_priv->ims_qmi, NULL, &txn,
+			 QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_V01,
+		IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_MSG_V01_MAX_MSG_LEN,
+		ims_private_service_wfc_call_twt_config_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Send Err: %d\n", ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("IMS->CNSS: TWT_CFG_RSP: QMI Wait Err: %d\n", ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("IMS->CNSS: TWT_CFG_RSP: Result: %d Err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+	ret = 0;
+out:
+	kfree(req);
+	kfree(resp);
+	return ret;
+}
+
+int cnss_process_twt_cfg_ind_event(struct cnss_plat_data *plat_priv,
+				   void *data)
+{
+	int ret;
+	struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data;
+
+	ret = cnss_ims_wfc_call_twt_cfg_send_sync(plat_priv, ind_msg);
+	kfree(data);
+	return ret;
+}
+
+static void cnss_wlfw_process_twt_cfg_ind(struct qmi_handle *qmi_wlfw,
+					  struct sockaddr_qrtr *sq,
+					  struct qmi_txn *txn,
+					  const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data;
+	struct wlfw_wfc_call_twt_config_ind_msg_v01 *event_data;
+
+	if (!txn) {
+		cnss_pr_err("FW->CNSS: TWT_CFG_IND: Spurious indication\n");
+		return;
+	}
+
+	if (!ind_msg) {
+		cnss_pr_err("FW->CNSS: TWT_CFG_IND: Invalid indication\n");
+		return;
+	}
+	cnss_pr_dbg("FW->CNSS: TWT_CFG_IND: %x %llx, %x %x, %x %x, %x %x, %x %x, %x %x\n",
+		    ind_msg->twt_sta_start_valid, ind_msg->twt_sta_start,
+		    ind_msg->twt_sta_int_valid, ind_msg->twt_sta_int,
+		    ind_msg->twt_sta_upo_valid, ind_msg->twt_sta_upo,
+		    ind_msg->twt_sta_sp_valid, ind_msg->twt_sta_sp,
+		    ind_msg->twt_sta_dl_valid, ind_msg->twt_sta_dl,
+		    ind_msg->twt_sta_config_changed_valid,
+		    ind_msg->twt_sta_config_changed);
+
+	event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL);
+	if (!event_data)
+		return;
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND, 0,
+			       event_data);
+}
+
+static struct qmi_msg_handler qmi_wlfw_msg_handlers[] = {
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01,
+		.ei = wlfw_request_mem_ind_msg_v01_ei,
+		.decoded_size = sizeof(struct wlfw_request_mem_ind_msg_v01),
+		.fn = cnss_wlfw_request_mem_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_FW_MEM_READY_IND_V01,
+		.ei = wlfw_fw_mem_ready_ind_msg_v01_ei,
+		.decoded_size = sizeof(struct wlfw_fw_mem_ready_ind_msg_v01),
+		.fn = cnss_wlfw_fw_mem_ready_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_FW_READY_IND_V01,
+		.ei = wlfw_fw_ready_ind_msg_v01_ei,
+		.decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01),
+		.fn = cnss_wlfw_fw_ready_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01,
+		.ei = wlfw_fw_init_done_ind_msg_v01_ei,
+		.decoded_size = sizeof(struct wlfw_fw_init_done_ind_msg_v01),
+		.fn = cnss_wlfw_fw_init_done_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01,
+		.ei = wlfw_pin_connect_result_ind_msg_v01_ei,
+		.decoded_size =
+			sizeof(struct wlfw_pin_connect_result_ind_msg_v01),
+		.fn = cnss_wlfw_pin_result_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_CAL_DONE_IND_V01,
+		.ei = wlfw_cal_done_ind_msg_v01_ei,
+		.decoded_size = sizeof(struct wlfw_cal_done_ind_msg_v01),
+		.fn = cnss_wlfw_cal_done_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01,
+		.ei = wlfw_qdss_trace_req_mem_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_qdss_trace_req_mem_ind_msg_v01),
+		.fn = cnss_wlfw_qdss_trace_req_mem_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_QDSS_TRACE_SAVE_IND_V01,
+		.ei = wlfw_qdss_trace_save_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_qdss_trace_save_ind_msg_v01),
+		.fn = cnss_wlfw_fw_mem_file_save_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_QDSS_TRACE_FREE_IND_V01,
+		.ei = wlfw_qdss_trace_free_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_qdss_trace_free_ind_msg_v01),
+		.fn = cnss_wlfw_qdss_trace_free_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_RESPOND_GET_INFO_IND_V01,
+		.ei = wlfw_respond_get_info_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_respond_get_info_ind_msg_v01),
+		.fn = cnss_wlfw_respond_get_info_ind_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_WFC_CALL_TWT_CONFIG_IND_V01,
+		.ei = wlfw_wfc_call_twt_config_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_wfc_call_twt_config_ind_msg_v01),
+		.fn = cnss_wlfw_process_twt_cfg_ind
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_WLFW_DRIVER_ASYNC_DATA_IND_V01,
+		.ei = wlfw_driver_async_data_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct wlfw_driver_async_data_ind_msg_v01),
+		.fn = cnss_wlfw_driver_async_data_ind_cb
+	},
+	{}
+};
+
+static int cnss_wlfw_connect_to_server(struct cnss_plat_data *plat_priv,
+				       void *data)
+{
+	struct cnss_qmi_event_server_arrive_data *event_data = data;
+	struct qmi_handle *qmi_wlfw = &plat_priv->qmi_wlfw;
+	struct sockaddr_qrtr sq = { 0 };
+	int ret = 0;
+
+	if (!event_data)
+		return -EINVAL;
+
+	sq.sq_family = AF_QIPCRTR;
+	sq.sq_node = event_data->node;
+	sq.sq_port = event_data->port;
+
+	ret = kernel_connect(qmi_wlfw->sock, (struct sockaddr *)&sq,
+			     sizeof(sq), 0);
+	if (ret < 0) {
+		cnss_pr_err("Failed to connect to QMI WLFW remote service port\n");
+		goto out;
+	}
+
+	set_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+	cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+
+	kfree(data);
+	return 0;
+
+out:
+	CNSS_QMI_ASSERT();
+	kfree(data);
+	return ret;
+}
+
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv, void *data)
+{
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_err("Unexpected WLFW server arrive\n");
+		CNSS_ASSERT(0);
+		return -EINVAL;
+	}
+
+	cnss_ignore_qmi_failure(false);
+
+	ret = cnss_wlfw_connect_to_server(plat_priv, data);
+	if (ret < 0)
+		goto out;
+
+	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
+	if (ret < 0) {
+		if (ret == -EALREADY)
+			ret = 0;
+		goto out;
+	}
+
+	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
+	if (ret < 0)
+		goto out;
+
+	return 0;
+
+out:
+	return ret;
+}
+
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	clear_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+	cnss_pr_info("QMI WLFW service disconnected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+
+	cnss_qmi_deinit(plat_priv);
+
+	clear_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state);
+
+	ret = cnss_qmi_init(plat_priv);
+	if (ret < 0) {
+		cnss_pr_err("QMI WLFW service registraton failed, ret\n", ret);
+		CNSS_ASSERT(0);
+	}
+	return 0;
+}
+
+static int wlfw_new_server(struct qmi_handle *qmi_wlfw,
+			   struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+	struct cnss_qmi_event_server_arrive_data *event_data;
+
+	if (plat_priv && test_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state)) {
+		cnss_pr_info("WLFW server delete in progress, Ignore server arrive, state: 0x%lx\n",
+			     plat_priv->driver_state);
+		return 0;
+	}
+
+	cnss_pr_dbg("WLFW server arriving: node %u port %u\n",
+		    service->node, service->port);
+
+	event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+	if (!event_data)
+		return -ENOMEM;
+
+	event_data->node = service->node;
+	event_data->port = service->port;
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+			       0, event_data);
+
+	return 0;
+}
+
+static void wlfw_del_server(struct qmi_handle *qmi_wlfw,
+			    struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
+
+	if (plat_priv && test_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state)) {
+		cnss_pr_info("WLFW server delete in progress, Ignore server delete, state: 0x%lx\n",
+			     plat_priv->driver_state);
+		return;
+	}
+
+	cnss_pr_dbg("WLFW server exiting\n");
+
+	if (plat_priv) {
+		cnss_ignore_qmi_failure(true);
+		set_bit(CNSS_QMI_DEL_SERVER, &plat_priv->driver_state);
+	}
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_SERVER_EXIT,
+			       0, NULL);
+}
+
+static struct qmi_ops qmi_wlfw_ops = {
+	.new_server = wlfw_new_server,
+	.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,
+			      &qmi_wlfw_ops, qmi_wlfw_msg_handlers);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize WLFW QMI handle, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = cnss_qmi_add_lookup(plat_priv);
+	if (ret < 0)
+		cnss_pr_err("Failed to add WLFW QMI lookup, err: %d\n", ret);
+
+out:
+	return ret;
+}
+
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
+{
+	qmi_handle_release(&plat_priv->qmi_wlfw);
+}
+
+int cnss_qmi_get_dms_mac(struct cnss_plat_data *plat_priv)
+{
+	struct dms_get_mac_address_req_msg_v01 req;
+	struct dms_get_mac_address_resp_msg_v01 resp;
+	struct qmi_txn txn;
+	int ret = 0;
+
+	if  (!test_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state)) {
+		cnss_pr_err("DMS QMI connection not established\n");
+		return -EINVAL;
+	}
+	cnss_pr_dbg("Requesting DMS MAC address");
+
+	memset(&resp, 0, sizeof(resp));
+	ret = qmi_txn_init(&plat_priv->qmi_dms, &txn,
+			   dms_get_mac_address_resp_msg_v01_ei, &resp);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize txn for dms, err: %d\n",
+			    ret);
+		goto out;
+	}
+	req.device = DMS_DEVICE_MAC_WLAN_V01;
+	ret = qmi_send_request(&plat_priv->qmi_dms, NULL, &txn,
+			       QMI_DMS_GET_MAC_ADDRESS_REQ_V01,
+			       DMS_GET_MAC_ADDRESS_REQ_MSG_V01_MAX_MSG_LEN,
+			       dms_get_mac_address_req_msg_v01_ei, &req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Failed to send QMI_DMS_GET_MAC_ADDRESS_REQ_V01, err: %d\n",
+			    ret);
+		goto out;
+	}
+	ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF);
+	if (ret < 0) {
+		cnss_pr_err("Failed to wait for QMI_DMS_GET_MAC_ADDRESS_RESP_V01, err: %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("QMI_DMS_GET_MAC_ADDRESS_REQ_V01 failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = -resp.resp.result;
+		goto out;
+	}
+	if (!resp.mac_address_valid ||
+	    resp.mac_address_len != QMI_WLFW_MAC_ADDR_SIZE_V01) {
+		cnss_pr_err("Invalid MAC address received from DMS\n");
+		plat_priv->dms.mac_valid = false;
+		goto out;
+	}
+	plat_priv->dms.mac_valid = true;
+	memcpy(plat_priv->dms.mac, resp.mac_address, QMI_WLFW_MAC_ADDR_SIZE_V01);
+	cnss_pr_info("Received DMS MAC: [%pM]\n", plat_priv->dms.mac);
+out:
+	return ret;
+}
+
+static int cnss_dms_connect_to_server(struct cnss_plat_data *plat_priv,
+				      unsigned int node, unsigned int port)
+{
+	struct qmi_handle *qmi_dms = &plat_priv->qmi_dms;
+	struct sockaddr_qrtr sq = {0};
+	int ret = 0;
+
+	sq.sq_family = AF_QIPCRTR;
+	sq.sq_node = node;
+	sq.sq_port = port;
+
+	ret = kernel_connect(qmi_dms->sock, (struct sockaddr *)&sq,
+			     sizeof(sq), 0);
+	if (ret < 0) {
+		cnss_pr_err("Failed to connect to QMI DMS remote service Node: %d Port: %d\n",
+			    node, port);
+		goto out;
+	}
+
+	set_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state);
+	cnss_pr_info("QMI DMS service connected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+out:
+	return ret;
+}
+
+static int dms_new_server(struct qmi_handle *qmi_dms,
+			  struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_dms, struct cnss_plat_data, qmi_dms);
+
+	if (!service)
+		return -EINVAL;
+
+	return cnss_dms_connect_to_server(plat_priv, service->node,
+					  service->port);
+}
+
+static void cnss_dms_server_exit_work(struct work_struct *work)
+{
+	int ret;
+	struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+
+	cnss_dms_deinit(plat_priv);
+
+	cnss_pr_info("QMI DMS Server Exit");
+	clear_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state);
+
+	ret = cnss_dms_init(plat_priv);
+	if (ret < 0)
+		cnss_pr_err("QMI DMS service registraton failed, ret\n", ret);
+}
+
+static DECLARE_WORK(cnss_dms_del_work, cnss_dms_server_exit_work);
+
+static void dms_del_server(struct qmi_handle *qmi_dms,
+			   struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi_dms, struct cnss_plat_data, qmi_dms);
+
+	if (!plat_priv)
+		return;
+
+	if (test_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state)) {
+		cnss_pr_info("DMS server delete or cnss remove in progress, Ignore server delete: 0x%lx\n",
+			     plat_priv->driver_state);
+		return;
+	}
+
+	set_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state);
+	clear_bit(CNSS_QMI_DMS_CONNECTED, &plat_priv->driver_state);
+	cnss_pr_info("QMI DMS service disconnected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+	schedule_work(&cnss_dms_del_work);
+}
+
+void cnss_cancel_dms_work(void)
+{
+	cancel_work_sync(&cnss_dms_del_work);
+}
+
+static struct qmi_ops qmi_dms_ops = {
+	.new_server = dms_new_server,
+	.del_server = dms_del_server,
+};
+
+int cnss_dms_init(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	ret = qmi_handle_init(&plat_priv->qmi_dms, DMS_QMI_MAX_MSG_LEN,
+			      &qmi_dms_ops, NULL);
+	if (ret < 0) {
+		cnss_pr_err("Failed to initialize DMS handle, err: %d\n", ret);
+		goto out;
+	}
+
+	ret = qmi_add_lookup(&plat_priv->qmi_dms, DMS_SERVICE_ID_V01,
+			     DMS_SERVICE_VERS_V01, 0);
+	if (ret < 0)
+		cnss_pr_err("Failed to add DMS lookup, err: %d\n", ret);
+out:
+	return ret;
+}
+
+void cnss_dms_deinit(struct cnss_plat_data *plat_priv)
+{
+	set_bit(CNSS_DMS_DEL_SERVER, &plat_priv->driver_state);
+	qmi_handle_release(&plat_priv->qmi_dms);
+}
+
+int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+	struct coex_antenna_switch_to_wlan_req_msg_v01 *req;
+	struct coex_antenna_switch_to_wlan_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending coex antenna switch_to_wlan\n");
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->antenna = plat_priv->antenna;
+
+	ret = qmi_txn_init(&plat_priv->coex_qmi, &txn,
+			   coex_antenna_switch_to_wlan_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Fail to init txn for coex antenna switch_to_wlan resp %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request
+		(&plat_priv->coex_qmi, NULL, &txn,
+		 QMI_COEX_SWITCH_ANTENNA_TO_WLAN_REQ_V01,
+		 COEX_ANTENNA_SWITCH_TO_WLAN_REQ_MSG_V01_MAX_MSG_LEN,
+		 coex_antenna_switch_to_wlan_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Fail to send coex antenna switch_to_wlan req %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, COEX_TIMEOUT);
+	if (ret < 0) {
+		cnss_pr_err("Coex antenna switch_to_wlan resp wait failed with ret %d\n",
+			    ret);
+		goto out;
+	} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Coex antenna switch_to_wlan request rejected, result:%d error:%d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = -resp->resp.result;
+		goto out;
+	}
+
+	if (resp->grant_valid)
+		plat_priv->grant = resp->grant;
+
+	cnss_pr_dbg("Coex antenna grant: 0x%llx\n", resp->grant);
+
+	kfree(resp);
+	kfree(req);
+	return 0;
+
+out:
+	kfree(resp);
+	kfree(req);
+	return ret;
+}
+
+int coex_antenna_switch_to_mdm_send_sync_msg(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+	struct coex_antenna_switch_to_mdm_req_msg_v01 *req;
+	struct coex_antenna_switch_to_mdm_resp_msg_v01 *resp;
+	struct qmi_txn txn;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending coex antenna switch_to_mdm\n");
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
+	req->antenna = plat_priv->antenna;
+
+	ret = qmi_txn_init(&plat_priv->coex_qmi, &txn,
+			   coex_antenna_switch_to_mdm_resp_msg_v01_ei, resp);
+	if (ret < 0) {
+		cnss_pr_err("Fail to init txn for coex antenna switch_to_mdm resp %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request
+		(&plat_priv->coex_qmi, NULL, &txn,
+		 QMI_COEX_SWITCH_ANTENNA_TO_MDM_REQ_V01,
+		 COEX_ANTENNA_SWITCH_TO_MDM_REQ_MSG_V01_MAX_MSG_LEN,
+		 coex_antenna_switch_to_mdm_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(&txn);
+		cnss_pr_err("Fail to send coex antenna switch_to_mdm req %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_txn_wait(&txn, COEX_TIMEOUT);
+	if (ret < 0) {
+		cnss_pr_err("Coex antenna switch_to_mdm resp wait failed with ret %d\n",
+			    ret);
+		goto out;
+	} else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Coex antenna switch_to_mdm 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(resp);
+	kfree(req);
+	return ret;
+}
+
+int cnss_send_subsys_restart_level_msg(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+	struct wlfw_subsys_restart_level_req_msg_v01 req;
+	struct wlfw_subsys_restart_level_resp_msg_v01 resp;
+	u8 pcss_enabled;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Can't send pcss cmd before fw ready\n");
+		return 0;
+	}
+
+	pcss_enabled = plat_priv->recovery_pcss_enabled;
+	cnss_pr_dbg("Sending pcss recovery status: %d\n", pcss_enabled);
+
+	req.restart_level_type_valid = 1;
+	req.restart_level_type = pcss_enabled;
+
+	ret = qmi_send_wait(&plat_priv->qmi_wlfw, &req, &resp,
+			    wlfw_subsys_restart_level_req_msg_v01_ei,
+			    wlfw_subsys_restart_level_resp_msg_v01_ei,
+			    QMI_WLFW_SUBSYS_RESTART_LEVEL_REQ_V01,
+			    WLFW_SUBSYS_RESTART_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
+			    QMI_WLFW_TIMEOUT_JF);
+
+	if (ret < 0)
+		cnss_pr_err("pcss recovery setting failed with ret %d\n", ret);
+	return ret;
+}
+
+static int coex_new_server(struct qmi_handle *qmi,
+			   struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi, struct cnss_plat_data, coex_qmi);
+	struct sockaddr_qrtr sq = { 0 };
+	int ret = 0;
+
+	cnss_pr_dbg("COEX server arrive: node %u port %u\n",
+		    service->node, service->port);
+
+	sq.sq_family = AF_QIPCRTR;
+	sq.sq_node = service->node;
+	sq.sq_port = service->port;
+	ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0);
+	if (ret < 0) {
+		cnss_pr_err("Fail to connect to remote service port\n");
+		return ret;
+	}
+
+	set_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state);
+	cnss_pr_dbg("COEX Server Connected: 0x%lx\n",
+		    plat_priv->driver_state);
+	return 0;
+}
+
+static void coex_del_server(struct qmi_handle *qmi,
+			    struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi, struct cnss_plat_data, coex_qmi);
+
+	cnss_pr_dbg("COEX server exit\n");
+
+	clear_bit(CNSS_COEX_CONNECTED, &plat_priv->driver_state);
+}
+
+static struct qmi_ops coex_qmi_ops = {
+	.new_server = coex_new_server,
+	.del_server = coex_del_server,
+};
+
+int cnss_register_coex_service(struct cnss_plat_data *plat_priv)
+{	int ret;
+
+	ret = qmi_handle_init(&plat_priv->coex_qmi,
+			      COEX_SERVICE_MAX_MSG_LEN,
+			      &coex_qmi_ops, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = qmi_add_lookup(&plat_priv->coex_qmi, COEX_SERVICE_ID_V01,
+			     COEX_SERVICE_VERS_V01, 0);
+	return ret;
+}
+
+void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv)
+{
+	qmi_handle_release(&plat_priv->coex_qmi);
+}
+
+/* IMS Service */
+static int ims_subscribe_for_indication_send_async(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+	struct ims_private_service_subscribe_for_indications_req_msg_v01 *req;
+	struct qmi_txn *txn;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending ASYNC ims subscribe for indication\n");
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	req->wfc_call_status_valid = 1;
+	req->wfc_call_status = 1;
+
+	txn = &plat_priv->txn;
+	ret = qmi_txn_init(&plat_priv->ims_qmi, txn, NULL, NULL);
+	if (ret < 0) {
+		cnss_pr_err("Fail to init txn for ims subscribe for indication resp %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_send_request
+	(&plat_priv->ims_qmi, NULL, txn,
+	QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01,
+	IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_MSG_V01_MAX_MSG_LEN,
+	ims_private_service_subscribe_ind_req_msg_v01_ei, req);
+	if (ret < 0) {
+		qmi_txn_cancel(txn);
+		cnss_pr_err("Fail to send ims subscribe for indication req %d\n",
+			    ret);
+		goto out;
+	}
+
+	kfree(req);
+	return 0;
+
+out:
+	kfree(req);
+	return ret;
+}
+
+static void ims_subscribe_for_indication_resp_cb(struct qmi_handle *qmi,
+						 struct sockaddr_qrtr *sq,
+						 struct qmi_txn *txn,
+						 const void *data)
+{
+	const
+	struct ims_private_service_subscribe_for_indications_rsp_msg_v01 *resp =
+		data;
+
+	cnss_pr_dbg("Received IMS subscribe indication response\n");
+
+	if (!txn) {
+		cnss_pr_err("spurious response\n");
+		return;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("IMS subscribe for indication request rejected, result:%d error:%d\n",
+			    resp->resp.result, resp->resp.error);
+		txn->result = -resp->resp.result;
+	}
+}
+
+int cnss_process_wfc_call_ind_event(struct cnss_plat_data *plat_priv,
+				    void *data)
+{
+	int ret;
+	struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data;
+
+	ret = cnss_wlfw_wfc_call_status_send_sync(plat_priv, ind_msg);
+	kfree(data);
+	return ret;
+}
+
+static void
+cnss_ims_process_wfc_call_ind_cb(struct qmi_handle *ims_qmi,
+				 struct sockaddr_qrtr *sq,
+				 struct qmi_txn *txn, const void *data)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(ims_qmi, struct cnss_plat_data, ims_qmi);
+	const
+	struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data;
+	struct ims_private_service_wfc_call_status_ind_msg_v01 *event_data;
+
+	if (!txn) {
+		cnss_pr_err("IMS->CNSS: WFC_CALL_IND: Spurious indication\n");
+		return;
+	}
+
+	if (!ind_msg) {
+		cnss_pr_err("IMS->CNSS: WFC_CALL_IND: Invalid indication\n");
+		return;
+	}
+	cnss_pr_dbg("IMS->CNSS: WFC_CALL_IND: %x, %x %x, %x %x, %x %llx, %x %x, %x %x\n",
+		    ind_msg->wfc_call_active, ind_msg->all_wfc_calls_held_valid,
+		    ind_msg->all_wfc_calls_held,
+		    ind_msg->is_wfc_emergency_valid, ind_msg->is_wfc_emergency,
+		    ind_msg->twt_ims_start_valid, ind_msg->twt_ims_start,
+		    ind_msg->twt_ims_int_valid, ind_msg->twt_ims_int,
+		    ind_msg->media_quality_valid, ind_msg->media_quality);
+
+	event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL);
+	if (!event_data)
+		return;
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_IMS_WFC_CALL_IND,
+			       0, event_data);
+}
+
+static struct qmi_msg_handler qmi_ims_msg_handlers[] = {
+	{
+		.type = QMI_RESPONSE,
+		.msg_id =
+		QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01,
+		.ei =
+		ims_private_service_subscribe_ind_rsp_msg_v01_ei,
+		.decoded_size = sizeof(struct
+		ims_private_service_subscribe_for_indications_rsp_msg_v01),
+		.fn = ims_subscribe_for_indication_resp_cb
+	},
+	{
+		.type = QMI_INDICATION,
+		.msg_id = QMI_IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_V01,
+		.ei = ims_private_service_wfc_call_status_ind_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct ims_private_service_wfc_call_status_ind_msg_v01),
+		.fn = cnss_ims_process_wfc_call_ind_cb
+	},
+	{}
+};
+
+static int ims_new_server(struct qmi_handle *qmi,
+			  struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi, struct cnss_plat_data, ims_qmi);
+	struct sockaddr_qrtr sq = { 0 };
+	int ret = 0;
+
+	cnss_pr_dbg("IMS server arrive: node %u port %u\n",
+		    service->node, service->port);
+
+	sq.sq_family = AF_QIPCRTR;
+	sq.sq_node = service->node;
+	sq.sq_port = service->port;
+	ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0);
+	if (ret < 0) {
+		cnss_pr_err("Fail to connect to remote service port\n");
+		return ret;
+	}
+
+	set_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state);
+	cnss_pr_dbg("IMS Server Connected: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	ret = ims_subscribe_for_indication_send_async(plat_priv);
+	return ret;
+}
+
+static void ims_del_server(struct qmi_handle *qmi,
+			   struct qmi_service *service)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(qmi, struct cnss_plat_data, ims_qmi);
+
+	cnss_pr_dbg("IMS server exit\n");
+
+	clear_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state);
+}
+
+static struct qmi_ops ims_qmi_ops = {
+	.new_server = ims_new_server,
+	.del_server = ims_del_server,
+};
+
+int cnss_register_ims_service(struct cnss_plat_data *plat_priv)
+{	int ret;
+
+	ret = qmi_handle_init(&plat_priv->ims_qmi,
+			      IMSPRIVATE_SERVICE_MAX_MSG_LEN,
+			      &ims_qmi_ops, qmi_ims_msg_handlers);
+	if (ret < 0)
+		return ret;
+
+	ret = qmi_add_lookup(&plat_priv->ims_qmi, IMSPRIVATE_SERVICE_ID_V01,
+			     IMSPRIVATE_SERVICE_VERS_V01, 0);
+	return ret;
+}
+
+void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv)
+{
+	qmi_handle_release(&plat_priv->ims_qmi);
+}

+ 356 - 0
qcom/opensource/wlan/platform/cnss2/qmi.h

@@ -0,0 +1,356 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+
+#ifndef _CNSS_QMI_H
+#define _CNSS_QMI_H
+
+#include "wlan_firmware_service_v01.h"
+
+struct cnss_plat_data;
+
+struct cnss_qmi_event_server_arrive_data {
+	unsigned int node;
+	unsigned int port;
+};
+
+struct cnss_mem_seg {
+	u64 addr;
+	u32 size;
+};
+
+struct cnss_qmi_event_fw_mem_file_save_data {
+	u32 total_size;
+	u32 mem_seg_len;
+	enum wlfw_mem_type_enum_v01 mem_type;
+	struct cnss_mem_seg mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+	char file_name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+};
+
+#ifdef CONFIG_CNSS2_QMI
+#include "coexistence_service_v01.h"
+#include "ip_multimedia_subsystem_private_service_v01.h"
+#include "device_management_service_v01.h"
+
+int cnss_qmi_init(struct cnss_plat_data *plat_priv);
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv);
+unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv, void *data);
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				 u32 bdf_type);
+int cnss_wlfw_tme_patch_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file);
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_aux_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+				  enum cnss_driver_mode mode);
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+				 struct cnss_wlan_enable_cfg *config,
+				 const char *host_version);
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+				     u32 offset, u32 mem_type,
+				     u32 data_len, u8 *data);
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+				      u32 offset, u32 mem_type,
+				      u32 data_len, u8 *data);
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+			    u8 fw_log_mode);
+int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_get_info_send_sync(struct cnss_plat_data *plat_priv, int type,
+				 void *cmd, int cmd_len);
+int cnss_process_wfc_call_ind_event(struct cnss_plat_data *plat_priv,
+				    void *data);
+int cnss_process_twt_cfg_ind_event(struct cnss_plat_data *plat_priv,
+				   void *data);
+int cnss_register_coex_service(struct cnss_plat_data *plat_priv);
+void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv);
+int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv);
+int coex_antenna_switch_to_mdm_send_sync_msg(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_register_ims_service(struct cnss_plat_data *plat_priv);
+void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv);
+void cnss_ignore_qmi_failure(bool ignore);
+int cnss_qmi_get_dms_mac(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_wlan_mac_req_send_sync(struct cnss_plat_data *plat_priv,
+				     u8 *mac, u32 mac_len);
+int cnss_dms_init(struct cnss_plat_data *plat_priv);
+void cnss_dms_deinit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_qdss_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_name,
+				  u32 total_size);
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file);
+int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv);
+int wlfw_qdss_trace_stop(struct cnss_plat_data *plat_priv, unsigned long long option);
+int cnss_wlfw_cal_report_req_send_sync(struct cnss_plat_data *plat_priv,
+				       u32 cal_file_download_size);
+int cnss_send_subsys_restart_level_msg(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv,
+					struct cnss_wfc_cfg cfg);
+void cnss_cancel_dms_work(void);
+#else
+#define QMI_WLFW_TIMEOUT_MS		10000
+
+static inline int cnss_qmi_init(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
+{
+}
+
+static inline
+unsigned int cnss_get_qmi_timeout(struct cnss_plat_data *plat_priv)
+{
+	return QMI_WLFW_TIMEOUT_MS;
+}
+
+static inline int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv,
+					  void *data)
+{
+	return 0;
+}
+
+static inline int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
+					       u32 bdf_type)
+{
+	return 0;
+}
+
+static inline int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline int cnss_wlfw_aux_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+				  enum cnss_driver_mode mode)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+				 struct cnss_wlan_enable_cfg *config,
+				 const char *host_version)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+				     u32 offset, u32 mem_type,
+				     u32 data_len, u8 *data)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+				      u32 offset, u32 mem_type,
+				      u32 data_len, u8 *data)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+			    u8 fw_log_mode)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_antenna_switch_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_antenna_grant_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_dynamic_feature_mask_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_get_info_send_sync(struct cnss_plat_data *plat_priv, int type,
+				 void *cmd, int cmd_len)
+{
+	return 0;
+}
+
+static inline
+int cnss_process_wfc_call_ind_event(struct cnss_plat_data *plat_priv,
+				    void *data)
+{
+	return 0;
+}
+
+static inline
+int cnss_process_twt_cfg_ind_event(struct cnss_plat_data *plat_priv,
+				   void *data)
+{
+	return 0;
+}
+
+static inline
+int cnss_register_coex_service(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+void cnss_unregister_coex_service(struct cnss_plat_data *plat_priv) {}
+
+static inline
+int coex_antenna_switch_to_wlan_send_sync_msg(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int coex_antenna_switch_to_mdm_send_sync_msg(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_qdss_trace_mem_info_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+int cnss_register_ims_service(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static inline
+void cnss_unregister_ims_service(struct cnss_plat_data *plat_priv) {}
+
+static inline
+int cnss_wlfw_send_pcie_gen_speed_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+void cnss_ignore_qmi_failure(bool ignore) {};
+static inline int cnss_qmi_get_dms_mac(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+int cnss_wlfw_wlan_mac_req_send_sync(struct cnss_plat_data *plat_priv,
+				     u8 *mac, u32 mac_len)
+{
+	return 0;
+}
+
+static inline int cnss_dms_init(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+int cnss_wlfw_qdss_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_name,
+				  u32 total_size)
+{
+	return 0;
+}
+
+int cnss_wlfw_tme_opt_file_dnld_send_sync(struct cnss_plat_data *plat_priv,
+				       enum wlfw_tme_lite_file_type_v01 file)
+{
+	return 0;
+}
+
+static inline void cnss_dms_deinit(struct cnss_plat_data *plat_priv) {}
+
+int wlfw_qdss_trace_start(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+int wlfw_qdss_trace_stop(struct cnss_plat_data *plat_priv, unsigned long long option)
+{
+	return 0;
+}
+
+static inline
+int cnss_wlfw_cal_report_req_send_sync(struct cnss_plat_data *plat_priv,
+				       u32 cal_file_download_size)
+{
+	return 0;
+}
+
+static inline
+int cnss_send_subsys_restart_level_msg(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+
+static void cnss_cancel_dms_work(void)
+{
+}
+
+int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv,
+					struct cnss_wfc_cfg cfg)
+{
+	return 0;
+}
+#endif /* CONFIG_CNSS2_QMI */
+
+#ifdef CONFIG_CNSS2_DEBUG
+static inline u32 cnss_get_host_build_type(void)
+{
+	return QMI_HOST_BUILD_TYPE_PRIMARY_V01;
+}
+#else
+static inline u32 cnss_get_host_build_type(void)
+{
+	return QMI_HOST_BUILD_TYPE_SECONDARY_V01;
+}
+#endif
+
+#endif /* _CNSS_QMI_H */

+ 380 - 0
qcom/opensource/wlan/platform/cnss2/reg.h

@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CNSS_REG_H
+#define _CNSS_REG_H
+
+#define QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET	0x310C
+#define PEACH_PCIE_REMAP_BAR_CTRL_OFFSET	0x3278
+
+#define QCA6390_CE_SRC_RING_REG_BASE		0xA00000
+#define QCA6390_CE_DST_RING_REG_BASE		0xA01000
+#define QCA6390_CE_COMMON_REG_BASE		0xA18000
+
+#define QCA6490_CE_SRC_RING_REG_BASE		0x1B80000
+#define QCA6490_CE_DST_RING_REG_BASE		0x1B81000
+#define QCA6490_CE_COMMON_REG_BASE		0x1B98000
+
+#define CE_SRC_RING_BASE_LSB_OFFSET		0x0
+#define CE_SRC_RING_BASE_MSB_OFFSET		0x4
+#define CE_SRC_RING_ID_OFFSET			0x8
+#define CE_SRC_RING_MISC_OFFSET			0x10
+#define CE_SRC_CTRL_OFFSET			0x58
+#define CE_SRC_R0_CE_CH_SRC_IS_OFFSET		0x5C
+#define CE_SRC_RING_HP_OFFSET			0x400
+#define CE_SRC_RING_TP_OFFSET			0x404
+
+#define CE_DEST_RING_BASE_LSB_OFFSET		0x0
+#define CE_DEST_RING_BASE_MSB_OFFSET		0x4
+#define CE_DEST_RING_ID_OFFSET			0x8
+#define CE_DEST_RING_MISC_OFFSET		0x10
+#define CE_DEST_CTRL_OFFSET			0xB0
+#define CE_CH_DST_IS_OFFSET			0xB4
+#define CE_CH_DEST_CTRL2_OFFSET			0xB8
+#define CE_DEST_RING_HP_OFFSET			0x400
+#define CE_DEST_RING_TP_OFFSET			0x404
+
+#define CE_STATUS_RING_BASE_LSB_OFFSET		0x58
+#define CE_STATUS_RING_BASE_MSB_OFFSET		0x5C
+#define CE_STATUS_RING_ID_OFFSET		0x60
+#define CE_STATUS_RING_MISC_OFFSET		0x68
+#define CE_STATUS_RING_HP_OFFSET		0x408
+#define CE_STATUS_RING_TP_OFFSET		0x40C
+
+#define CE_COMMON_GXI_ERR_INTS			0x14
+#define CE_COMMON_GXI_ERR_STATS			0x18
+#define CE_COMMON_GXI_WDOG_STATUS		0x2C
+#define CE_COMMON_TARGET_IE_0			0x48
+#define CE_COMMON_TARGET_IE_1			0x4C
+
+#define CE_REG_INTERVAL				0x2000
+
+#define SHADOW_REG_COUNT			36
+#define SHADOW_REG_LEN_BYTES			4
+#define PCIE_SHADOW_REG_VALUE_0			0x8FC
+#define PCIE_SHADOW_REG_VALUE_1			0x900
+#define PCIE_SHADOW_REG_VALUE_34		0x984
+#define PCIE_SHADOW_REG_VALUE_35		0x988
+
+#define SHADOW_REG_INTER_COUNT			43
+#define PCIE_SHADOW_REG_INTER_0			0x1E05000
+
+#define PCIE_MHI_TIME_LOW			0xA28
+#define PCIE_MHI_TIME_HIGH			0xA2C
+
+#define QDSS_APB_DEC_CSR_BASE			0x1C01000
+
+#define QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET	0x6C
+#define QDSS_APB_DEC_CSR_PRESERVEETF_OFFSET	0x70
+#define QDSS_APB_DEC_CSR_PRESERVEETR0_OFFSET	0x74
+#define QDSS_APB_DEC_CSR_PRESERVEETR1_OFFSET	0x78
+
+#define MAX_UNWINDOWED_ADDRESS			0x80000
+#define WINDOW_ENABLE_BIT			0x40000000
+#define WINDOW_SHIFT				19
+#define WINDOW_VALUE_MASK			0x3F
+#define WINDOW_START				MAX_UNWINDOWED_ADDRESS
+#define WINDOW_RANGE_MASK			0x7FFFF
+
+#define TIME_SYNC_ENABLE			0x80000000
+#define TIME_SYNC_CLEAR				0x0
+
+#define QCA6390_DEBUG_PBL_LOG_SRAM_START	0x01403D58
+#define QCA6390_DEBUG_PBL_LOG_SRAM_MAX_SIZE	80
+#define QCA6390_DEBUG_SBL_LOG_SRAM_MAX_SIZE	44
+
+#define QCA6490_DEBUG_PBL_LOG_SRAM_START	0x01403DA0
+#define QCA6490_DEBUG_PBL_LOG_SRAM_MAX_SIZE	40
+#define QCA6490_DEBUG_SBL_LOG_SRAM_MAX_SIZE	48
+
+#define KIWI_DEBUG_PBL_LOG_SRAM_START		0x01403D98
+#define KIWI_DEBUG_PBL_LOG_SRAM_MAX_SIZE	40
+#define KIWI_DEBUG_SBL_LOG_SRAM_MAX_SIZE	48
+#define KIWI_PBL_BOOTSTRAP_STATUS		0x01A10008
+
+#define MANGO_DEBUG_PBL_LOG_SRAM_START		0x01403D98
+#define MANGO_DEBUG_PBL_LOG_SRAM_MAX_SIZE	40
+#define MANGO_DEBUG_SBL_LOG_SRAM_MAX_SIZE	48
+#define MANGO_PBL_BOOTSTRAP_STATUS		0x01A10008
+
+#define PEACH_DEBUG_PBL_LOG_SRAM_START		0x01403640
+#define PEACH_DEBUG_PBL_LOG_SRAM_MAX_SIZE	40
+#define PEACH_DEBUG_SBL_LOG_SRAM_MAX_SIZE	48
+#define PEACH_PBL_BOOTSTRAP_STATUS		0x01A10008
+
+#define TCSR_PBL_LOGGING_REG			0x01B000F8
+#define PCIE_BHI_ERRDBG2_REG			0x01E0E238
+#define PCIE_BHI_ERRDBG3_REG			0x01E0E23C
+#define PBL_WLAN_BOOT_CFG			0x01E22B34
+#define PBL_BOOTSTRAP_STATUS			0x01910008
+#define SRAM_START				0x01400000
+#define SRAM_END				0x01800000
+#define SRAM_DUMP_SIZE				0x400000
+
+#define QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG 0x01E04234
+#define QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG_VAL 0xDEAD1234
+#define PEACH_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG 0x01E04334
+#define PEACH_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG_VAL 0xDEAD1334
+#define QCA6390_PCIE_PCIE_WCSS_STATUS_FOR_DEBUG_LOW_PCIE_LOCAL_REG 0x01E03140
+#define PEACH_PCIE_PCIE_WCSS_STATUS_FOR_DEBUG_LOW_PCIE_LOCAL_REG 0x01E03284
+#define QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG 0x1E04054
+#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
+#define QCA6390_PCIE_PCIE_PARF_INT_STATUS 0x01E08220
+#define QCA6390_PCIE_PCIE_INT_ALL_STATUS 0x01E08224
+#define QCA6390_PCIE_PCIE_INT_ALL_MASK 0x01E0822C
+#define QCA6390_PCIE_PCIE_PARF_BDF_TO_SID_CFG 0x01E0AC00
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4 0x01E08530
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_3 0x01E0852c
+#define QCA6390_PCIE_PCIE_PARF_MHI_CLOCK_RESET_CTRL 0x01E08174
+#define QCA6390_PCIE_PCIE_PARF_MHI_BASE_ADDR_LOWER 0x01E08178
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_STATUS 0x01E084D0
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_CFG 0x01E084d4
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2 0x01E0ec88
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1SUB 0x01E0ec08
+#define QCA6390_PCIE_PCIE_CORE_CONFIG 0x01E08640
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L2 0x01E0EC04
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1 0x01E0EC0C
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L1 0x01E0EC84
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_HIGH 0x01E030C8
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_LOW 0x01E030CC
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_HIGH 0x01E0313C
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_LOW 0x01E03140
+#define PEACH_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_HIGH 0x01E03214
+#define PEACH_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_LOW 0x01E03218
+#define PEACH_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_HIGH 0x01E03280
+#define PEACH_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_LOW 0x01E03284
+#define QCA6390_PCIE_PCIE_BHI_EXECENV_REG 0x01E0E228
+
+#define QCA6390_GCC_DEBUG_CLK_CTL 0x001E4025C
+
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_PLL_MODE 0x00D00200
+#define QCA6390_WCSS_WFSS_PMM_WFSS_PMM_R0_PMM_CTRL 0x00B60164
+#define QCA6390_WCSS_PMM_TOP_PMU_CX_CSR 0x00B70080
+#define QCA6390_WCSS_PMM_TOP_AON_INT_RAW_STAT 0x00B700E0
+#define QCA6390_WCSS_PMM_TOP_AON_INT_EN 0x00B700D0
+#define QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_STS 0x00B70020
+#define QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_CTL 0x00B7001C
+#define QCA6390_WCSS_PMM_TOP_TESTBUS_STS 0x00B70028
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG 0x00DB0008
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG_MSK 0x20
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL 0x00D02000
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE 0x00D02004
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_STS 0x00DB000C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_CTL 0x00DB0030
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_0 0x00DB0400
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_9 0x00DB0424
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS0 0x00D90380
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS1 0x00D90384
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS2 0x00D90388
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS3 0x00D9038C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS4 0x00D90390
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS5 0x00D90394
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS6 0x00D90398
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE0 0x00D90100
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE1 0x00D90104
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE2 0x00D90108
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE3 0x00D9010C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE4 0x00D90110
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE5 0x00D90114
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE6 0x00D90118
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING0 0x00D90500
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING1 0x00D90504
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING2 0x00D90508
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING3 0x00D9050C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING4 0x00D90510
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING5 0x00D90514
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING6 0x00D90518
+#define QCA6390_WCSS_CC_WCSS_UMAC_NOC_CBCR 0x00C3029C
+#define QCA6390_WCSS_CC_WCSS_UMAC_AHB_CBCR 0x00C302BC
+#define QCA6390_WCSS_CC_WCSS_UMAC_GDSCR 0x00C30298
+#define QCA6390_WCSS_CC_WCSS_WLAN1_GDSCR 0x00C300C4
+#define QCA6390_WCSS_CC_WCSS_WLAN2_GDSCR 0x00C30138
+#define QCA6390_WCSS_PMM_TOP_PMM_INT_CLR 0x00B70168
+#define QCA6390_WCSS_PMM_TOP_AON_INT_STICKY_EN 0x00B700D8
+
+#define QCA6390_TLMM_GPIO_IN_OUT57 0x01839004
+#define QCA6390_TLMM_GPIO_INTR_CFG57 0x01839008
+#define QCA6390_TLMM_GPIO_INTR_STATUS57 0x0183900C
+#define QCA6390_TLMM_GPIO_IN_OUT59 0x0183b004
+#define QCA6390_TLMM_GPIO_INTR_CFG59 0x0183b008
+#define QCA6390_TLMM_GPIO_INTR_STATUS59 0x0183b00C
+
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_STATUS_REG2 0x00B6017C
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_STATUS_REG2 0x00B60190
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN2_CFG_REG1 0x00B6018C
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN1_CFG_REG1 0x00B60178
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_APS_STATUS_REG1 0x00B600B0
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_APS_STATUS_REG1 0x00B60044
+
+#define WLAON_SOC_POWER_CTRL 0x01F80000
+#define WLAON_SOC_PWR_WDG_BARK_THRSHD 0x1F80004
+#define WLAON_SOC_PWR_WDG_BITE_THRSHD 0x1F80008
+#define WLAON_SW_COLD_RESET 0x1F8000C
+#define WLAON_RFA_MEM_SLP_NRET_N_OVERRIDE 0x1F8001C
+#define WLAON_GDSC_DELAY_SETTING 0x1F80024
+#define WLAON_GDSC_DELAY_SETTING2 0x1F80028
+#define WLAON_WL_PWR_STATUS_REG 0x1F8002C
+#define WLAON_WL_AON_DBG_CFG_REG 0x1F80030
+#define WLAON_WL_AON_DBG_ENABLE_GRP0_REG 0x1F80034
+#define WLAON_WL_AON_DBG_ENABLE_GRP1_REG 0x1F80038
+#define WLAON_WL_AON_APM_CFG_CTRL0 0x1F80040
+#define WLAON_WL_AON_APM_CFG_CTRL1 0x1F80044
+#define WLAON_WL_AON_APM_CFG_CTRL2 0x1F80048
+#define WLAON_WL_AON_APM_CFG_CTRL3 0x1F8004C
+#define WLAON_WL_AON_APM_CFG_CTRL4 0x1F80050
+#define WLAON_WL_AON_APM_CFG_CTRL5 0x1F80054
+#define WLAON_WL_AON_APM_CFG_CTRL5_1 0x1F80058
+#define WLAON_WL_AON_APM_CFG_CTRL6 0x1F8005C
+#define WLAON_WL_AON_APM_CFG_CTRL6_1 0x1F80060
+#define WLAON_WL_AON_APM_CFG_CTRL7 0x1F80064
+#define WLAON_WL_AON_APM_CFG_CTRL8 0x1F80068
+#define WLAON_WL_AON_APM_CFG_CTRL8_1 0x1F8006C
+#define WLAON_WL_AON_APM_CFG_CTRL9 0x1F80070
+#define WLAON_WL_AON_APM_CFG_CTRL9_1 0x1F80074
+#define WLAON_WL_AON_APM_CFG_CTRL10 0x1F80078
+#define WLAON_WL_AON_APM_CFG_CTRL11 0x1F8007C
+#define WLAON_WL_AON_APM_CFG_CTRL12 0x1F80080
+#define WLAON_WL_AON_APM_OVERRIDE_REG 0x1F800B0
+#define WLAON_WL_AON_CXPC_REG 0x1F800B4
+#define WLAON_WL_AON_APM_STATUS0 0x1F800C0
+#define WLAON_WL_AON_APM_STATUS1 0x1F800C4
+#define WLAON_WL_AON_APM_STATUS2 0x1F800C8
+#define WLAON_WL_AON_APM_STATUS3 0x1F800CC
+#define WLAON_WL_AON_APM_STATUS4 0x1F800D0
+#define WLAON_WL_AON_APM_STATUS5 0x1F800D4
+#define WLAON_WL_AON_APM_STATUS6 0x1F800D8
+#define WLAON_GLOBAL_COUNTER_CTRL1 0x1F80100
+#define WLAON_GLOBAL_COUNTER_CTRL6 0x1F80108
+#define WLAON_GLOBAL_COUNTER_CTRL7 0x1F8010C
+#define WLAON_GLOBAL_COUNTER_CTRL3 0x1F80118
+#define WLAON_GLOBAL_COUNTER_CTRL4 0x1F8011C
+#define WLAON_GLOBAL_COUNTER_CTRL5 0x1F80120
+#define WLAON_GLOBAL_COUNTER_CTRL8 0x1F801F0
+#define WLAON_GLOBAL_COUNTER_CTRL2 0x1F801F4
+#define WLAON_GLOBAL_COUNTER_CTRL9 0x1F801F8
+#define WLAON_RTC_CLK_CAL_CTRL1 0x1F80200
+#define WLAON_RTC_CLK_CAL_CTRL2 0x1F80204
+#define WLAON_RTC_CLK_CAL_CTRL3 0x1F80208
+#define WLAON_RTC_CLK_CAL_CTRL4 0x1F8020C
+#define WLAON_RTC_CLK_CAL_CTRL5 0x1F80210
+#define WLAON_RTC_CLK_CAL_CTRL6 0x1F80214
+#define WLAON_RTC_CLK_CAL_CTRL7 0x1F80218
+#define WLAON_RTC_CLK_CAL_CTRL8 0x1F8021C
+#define WLAON_RTC_CLK_CAL_CTRL9 0x1F80220
+#define WLAON_WCSSAON_CONFIG_REG 0x1F80300
+#define WLAON_WLAN_OEM_DEBUG_REG 0x1F80304
+#define WLAON_WLAN_RAM_DUMP_REG 0x1F80308
+#define WLAON_QDSS_WCSS_REG 0x1F8030C
+#define WLAON_QDSS_WCSS_ACK 0x1F80310
+#define WLAON_WL_CLK_CNTL_KDF_REG 0x1F80314
+#define WLAON_WL_CLK_CNTL_PMU_HFRC_REG 0x1F80318
+#define WLAON_QFPROM_PWR_CTRL_REG 0x1F8031C
+#define QFPROM_PWR_CTRL_VDD4BLOW_SW_EN_MASK 0x4
+#define QFPROM_PWR_CTRL_SHUTDOWN_EN_MASK 0x1
+#define WLAON_DLY_CONFIG 0x1F80400
+#define WLAON_WLAON_Q6_IRQ_REG 0x1F80404
+#define WLAON_PCIE_INTF_SW_CFG_REG 0x1F80408
+#define WLAON_PCIE_INTF_STICKY_SW_CFG_REG 0x1F8040C
+#define WLAON_PCIE_INTF_PHY_SW_CFG_REG 0x1F80410
+#define WLAON_PCIE_INTF_PHY_NOCSR_SW_CFG_REG 0x1F80414
+#define WLAON_Q6_COOKIE_BIT 0x1F80500
+#define WLAON_WARM_SW_ENTRY 0x1F80504
+#define WLAON_RESET_DBG_SW_ENTRY 0x1F80508
+#define WLAON_WL_PMUNOC_CFG_REG 0x1F8050C
+#define WLAON_RESET_CAUSE_CFG_REG 0x1F80510
+#define WLAON_SOC_RESET_CAUSE_SHADOW_REG 0x1F80608
+#define WLAON_SOC_WCSSAON_WAKEUP_IRQ_7_EN_REG 0x1F80514
+#define WLAON_DEBUG 0x1F80600
+#define WLAON_SOC_PARAMETERS 0x1F80604
+#define WLAON_WLPM_SIGNAL 0x1F80608
+#define WLAON_SOC_RESET_CAUSE_REG 0x1F8060C
+#define WLAON_WAKEUP_PCIE_SOC_REG 0x1F80610
+#define WLAON_PBL_STACK_CANARY 0x1F80614
+#define WLAON_MEM_TOT_NUM_GRP_REG 0x1F80618
+#define WLAON_MEM_TOT_BANKS_IN_GRP0_REG 0x1F8061C
+#define WLAON_MEM_TOT_BANKS_IN_GRP1_REG 0x1F80620
+#define WLAON_MEM_TOT_BANKS_IN_GRP2_REG 0x1F80624
+#define WLAON_MEM_TOT_BANKS_IN_GRP3_REG 0x1F80628
+#define WLAON_MEM_TOT_SIZE_IN_GRP0_REG 0x1F8062C
+#define WLAON_MEM_TOT_SIZE_IN_GRP1_REG 0x1F80630
+#define WLAON_MEM_TOT_SIZE_IN_GRP2_REG 0x1F80634
+#define WLAON_MEM_TOT_SIZE_IN_GRP3_REG 0x1F80638
+#define WLAON_MEM_SLP_NRET_OVERRIDE_GRP0_REG 0x1F8063C
+#define WLAON_MEM_SLP_NRET_OVERRIDE_GRP1_REG 0x1F80640
+#define WLAON_MEM_SLP_NRET_OVERRIDE_GRP2_REG 0x1F80644
+#define WLAON_MEM_SLP_NRET_OVERRIDE_GRP3_REG 0x1F80648
+#define WLAON_MEM_SLP_RET_OVERRIDE_GRP0_REG 0x1F8064C
+#define WLAON_MEM_SLP_RET_OVERRIDE_GRP1_REG 0x1F80650
+#define WLAON_MEM_SLP_RET_OVERRIDE_GRP2_REG 0x1F80654
+#define WLAON_MEM_SLP_RET_OVERRIDE_GRP3_REG 0x1F80658
+#define WLAON_MEM_CNT_SEL_REG 0x1F8065C
+#define WLAON_MEM_NO_EXTBHS_REG 0x1F80660
+#define WLAON_MEM_DEBUG_REG 0x1F80664
+#define WLAON_MEM_DEBUG_BUS_REG 0x1F80668
+#define WLAON_MEM_REDUN_CFG_REG 0x1F8066C
+#define WLAON_WL_AON_SPARE2 0x1F80670
+#define WLAON_VSEL_CFG_FOR_WL_RET_DISABLE_REG 0x1F80680
+#define WLAON_BTFM_WLAN_IPC_STATUS_REG 0x1F80690
+#define WLAON_MPM_COUNTER_CHICKEN_BITS 0x1F806A0
+#define WLAON_WLPM_CHICKEN_BITS 0x1F806A4
+#define WLAON_PCIE_PHY_PWR_REG 0x1F806A8
+#define WLAON_WL_CLK_CNTL_PMU_LPO2M_REG 0x1F806AC
+#define WLAON_WL_SS_ROOT_CLK_SWITCH_REG 0x1F806B0
+#define WLAON_POWERCTRL_PMU_REG 0x1F806B4
+#define WLAON_POWERCTRL_MEM_REG 0x1F806B8
+#define WLAON_PCIE_PWR_CTRL_REG 0x01F806BC
+#define WLAON_SOC_PWR_PROFILE_REG 0x1F806C0
+#define WLAON_WCSSAON_PCIE_SR_STATUS_HI_REG 0x01F806C4
+#define WLAON_WCSSAON_PCIE_SR_STATUS_LO_REG 0x1F806C8
+#define WLAON_WCSS_TCSR_PMM_SR_STATUS_HI_REG 0x1F806CC
+#define WLAON_WCSS_TCSR_PMM_SR_STATUS_LO_REG 0x1F806D0
+#define WLAON_MEM_SVS_CFG_REG 0x1F806D4
+#define WLAON_CMN_AON_MISC_REG 0x1F806D8
+#define WLAON_INTR_STATUS 0x1F80700
+#define WLAON_INTR_ENABLE 0x1F807040
+#define WLAON_NOC_DBG_BUS_SEL_REG 0x1F80708
+#define WLAON_NOC_DBG_BUS_REG 0x1F8070C
+#define WLAON_WL_CTRL_MISC_REG 0x1F80710
+#define WLAON_DBG_STATUS0 0x1F80720
+#define WLAON_DBG_STATUS1 0x1F80724
+#define WLAON_TIMERSYNC_OFFSET_L 0x1F80730
+#define WLAON_TIMERSYNC_OFFSET_H 0x1F80734
+#define WLAON_PMU_LDO_SETTLE_REG 0x1F80740
+
+#define QCA6390_SYSPM_SYSPM_PWR_STATUS 0x1F82000
+#define QCA6390_SYSPM_DBG_BTFM_AON_REG 0x1F82004
+#define QCA6390_SYSPM_DBG_BUS_SEL_REG 0x1F82008
+#define QCA6390_SYSPM_WCSSAON_SR_STATUS 0x1F8200C
+
+/* PCIE SOC scratch registers, address same for QCA6390 & QCA6490*/
+#define PCIE_SCRATCH_0_SOC_PCIE_REG 0x1E04040
+#define PCIE_SCRATCH_1_SOC_PCIE_REG 0x1E04044
+#define PCIE_SCRATCH_2_SOC_PCIE_REG 0x1E0405C
+
+/* PCIE BHIE DEBUG registers */
+#define PCIE_PCIE_BHIE_DEBUG_0 0x1E0E1C0
+#define PCIE_PCIE_BHIE_DEBUG_1 0x1E0E1C4
+#define PCIE_PCIE_BHIE_DEBUG_2 0x1E0E1C8
+#define PCIE_PCIE_BHIE_DEBUG_3 0x1E0E1CC
+#define PCIE_PCIE_BHIE_DEBUG_4 0x1E0E1D0
+#define PCIE_PCIE_BHIE_DEBUG_5 0x1E0E1D4
+#define PCIE_PCIE_BHIE_DEBUG_6 0x1E0E1D8
+#define PCIE_PCIE_BHIE_DEBUG_7 0x1E0E1DC
+#define PCIE_PCIE_BHIE_DEBUG_8 0x1E0E1E0
+#define PCIE_PCIE_BHIE_DEBUG_9 0x1E0E1E4
+#define PCIE_PCIE_BHIE_DEBUG_10 0x1E0E1E8
+
+#define GCC_GCC_SPARE_REG_1 0x1E40310
+#define GCC_PRE_ARES_DEBUG_TIMER_VAL 0x1E40270
+
+#define QCN7605_WINDOW_ENABLE_BIT       0x80000000
+#endif

+ 12 - 0
qcom/opensource/wlan/platform/cnss2/sun_consolidate_defconfig

@@ -0,0 +1,12 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS2_DEBUG=y

+ 11 - 0
qcom/opensource/wlan/platform/cnss2/sun_gki_defconfig

@@ -0,0 +1,11 @@
+CONFIG_CNSS2=m
+CONFIG_CNSS_OUT_OF_TREE=y
+CONFIG_CNSS2_QMI=y
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_BUS_AUTO_SUSPEND=y
+CONFIG_CNSS2_SSR_DRIVER_DUMP=y
+CONFIG_CNSS_HW_SECURE_DISABLE=y
+CONFIG_CNSS_HW_SECURE_SMEM=y
+CONFIG_CNSS2_SMMU_DB_SUPPORT=y
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_WCNSS_MEM_PRE_ALLOC=m

+ 14 - 0
qcom/opensource/wlan/platform/cnss_genl/Kconfig

@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config CNSS_GENL
+	tristate "CNSS Generic Netlink Socket Driver"
+	help
+	  This module creates generic netlink family "CLD80211". This can be
+	  used by cld driver and userspace utilities to communicate over
+	  netlink sockets. This module creates different multicast groups to
+	  facilitate the same.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree

+ 9 - 0
qcom/opensource/wlan/platform/cnss_genl/Makefile

@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ccflags-y += -Wmissing-prototypes
+
+ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
+endif
+
+obj-$(CONFIG_CNSS_GENL) := cnss_nl.o

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/anorak_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/anorak_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/blair_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/blair_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 255 - 0
qcom/opensource/wlan/platform/cnss_genl/cnss_nl.c

@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <net/genetlink.h>
+#ifdef CONFIG_CNSS_OUT_OF_TREE
+#include "cnss_nl.h"
+#else
+#include <net/cnss_nl.h>
+#endif
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/version.h>
+
+#define CLD80211_GENL_NAME "cld80211"
+
+#define CLD80211_MULTICAST_GROUP_SVC_MSGS       "svc_msgs"
+#define CLD80211_MULTICAST_GROUP_HOST_LOGS      "host_logs"
+#define CLD80211_MULTICAST_GROUP_FW_LOGS        "fw_logs"
+#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS  "per_pkt_stats"
+#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS    "diag_events"
+#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS   "fatal_events"
+#define CLD80211_MULTICAST_GROUP_OEM_MSGS       "oem_msgs"
+
+static const struct genl_multicast_group nl_mcgrps[] = {
+	[CLD80211_MCGRP_SVC_MSGS] = { .name =
+			CLD80211_MULTICAST_GROUP_SVC_MSGS},
+	[CLD80211_MCGRP_HOST_LOGS] = { .name =
+			CLD80211_MULTICAST_GROUP_HOST_LOGS},
+	[CLD80211_MCGRP_FW_LOGS] = { .name =
+			CLD80211_MULTICAST_GROUP_FW_LOGS},
+	[CLD80211_MCGRP_PER_PKT_STATS] = { .name =
+			CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
+	[CLD80211_MCGRP_DIAG_EVENTS] = { .name =
+			CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
+	[CLD80211_MCGRP_FATAL_EVENTS] = { .name =
+			CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
+	[CLD80211_MCGRP_OEM_MSGS] = { .name =
+			CLD80211_MULTICAST_GROUP_OEM_MSGS},
+};
+
+struct cld_ops {
+	cld80211_cb cb;
+	void *cb_ctx;
+};
+
+struct cld80211_nl_data {
+	struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
+};
+
+static struct cld80211_nl_data nl_data;
+
+static inline struct cld80211_nl_data *get_local_ctx(void)
+{
+	return &nl_data;
+}
+
+static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
+
+/* policy for the attributes */
+static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = {
+	[CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
+	[CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
+				 .len = CLD80211_MAX_NL_DATA },
+	[CLD80211_ATTR_META_DATA] = { .type = NLA_BINARY,
+				 .len = CLD80211_MAX_NL_DATA },
+	[CLD80211_ATTR_CMD] = { .type = NLA_U32 },
+	[CLD80211_ATTR_CMD_TAG_DATA] = { .type = NLA_NESTED },
+};
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0))
+static int cld80211_pre_doit(const struct genl_split_ops *ops,
+			     struct sk_buff *skb,
+			     struct genl_info *info)
+{
+	u8 cmd_id = ops->cmd;
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
+		return -EOPNOTSUPP;
+	}
+	info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
+	info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
+
+	return 0;
+}
+#else
+static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
+			     struct genl_info *info)
+{
+	u8 cmd_id = ops->cmd;
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
+		return -EOPNOTSUPP;
+	}
+	info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
+	info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
+
+	return 0;
+}
+#endif
+/* The netlink family */
+static struct genl_family cld80211_fam __ro_after_init = {
+	.name = CLD80211_GENL_NAME,
+	.hdrsize = 0,			/* no private header */
+	.version = 1,			/* no particular meaning now */
+	.maxattr = CLD80211_ATTR_MAX,
+	.policy = cld80211_policy,
+	.netnsok = true,
+	.pre_doit = cld80211_pre_doit,
+	.post_doit = NULL,
+	.module = THIS_MODULE,
+	.ops = nl_ops,
+	.n_ops = ARRAY_SIZE(nl_ops),
+	.mcgrps = nl_mcgrps,
+	.n_mcgrps = ARRAY_SIZE(nl_mcgrps),
+};
+
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
+{
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	pr_debug("CLD80211: Registering command: %d\n", cmd_id);
+	if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+		return -EINVAL;
+	}
+
+	nl->cld_ops[cmd_id - 1].cb = func;
+	nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
+
+	return 0;
+}
+EXPORT_SYMBOL(register_cld_cmd_cb);
+
+int deregister_cld_cmd_cb(u8 cmd_id)
+{
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
+	if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+		return -EINVAL;
+	}
+
+	nl->cld_ops[cmd_id - 1].cb = NULL;
+	nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(deregister_cld_cmd_cb);
+
+struct genl_family *cld80211_get_genl_family(void)
+{
+	return &cld80211_fam;
+}
+EXPORT_SYMBOL(cld80211_get_genl_family);
+
+static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
+{
+	cld80211_cb cld_cb;
+	void *cld_ctx;
+
+	cld_cb = info->user_ptr[0];
+
+	if (!cld_cb) {
+		pr_err("CLD80211: Not supported\n");
+		return -EOPNOTSUPP;
+	}
+	cld_ctx = info->user_ptr[1];
+
+	if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
+		cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+		       nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+		       cld_ctx, info->snd_portid);
+	} else {
+		pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __cld80211_init(void)
+{
+	int err, i;
+
+	memset(&nl_ops[0], 0, sizeof(nl_ops));
+
+	pr_info("CLD80211: Initializing\n");
+	for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
+		nl_ops[i].cmd = i + 1;
+		nl_ops[i].doit = cld80211_doit;
+		nl_ops[i].flags = GENL_ADMIN_PERM;
+	}
+
+	err = genl_register_family(&cld80211_fam);
+	if (err) {
+		pr_err("CLD80211: Failed to register cld80211 family: %d\n",
+		       err);
+	}
+
+	return err;
+}
+
+static void __cld80211_exit(void)
+{
+	genl_unregister_family(&cld80211_fam);
+}
+
+/**
+ * cld80211_is_valid_dt_node_found - Check if valid device tree node present
+ *
+ * Valid device tree node means a node with "qcom,wlan" property present and
+ * "status" property not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool cld80211_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_node_with_property(dn, "qcom,wlan") {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+static int __init cld80211_init(void)
+{
+	if (!cld80211_is_valid_dt_node_found())
+		return -ENODEV;
+
+	return __cld80211_init();
+}
+
+static void __exit cld80211_exit(void)
+{
+	__cld80211_exit();
+}
+
+module_init(cld80211_init);
+module_exit(cld80211_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS generic netlink module");

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/monaco_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/monaco_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/niobe_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/niobe_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/pineapple_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/pineapple_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/pitti_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/pitti_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/sun_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/sun_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/volcano_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_genl/volcano_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_CNSS_GENL=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 14 - 0
qcom/opensource/wlan/platform/cnss_prealloc/Kconfig

@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config WCNSS_MEM_PRE_ALLOC
+	tristate "WCNSS pre-alloc memory support"
+	help
+	  Pre-allocate memory for the WLAN driver module.
+	  This feature enable cld wlan driver to use pre allocated memory
+	  for it's internal usage and release it to back to pre allocated pool.
+	  This memory is allocated at the cold boot time.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree

+ 10 - 0
qcom/opensource/wlan/platform/cnss_prealloc/Makefile

@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ccflags-y += -Wmissing-prototypes
+
+ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/cnss_utils
+endif
+
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc.o

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/anorak_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/anorak_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/blair_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/blair_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 406 - 0
qcom/opensource/wlan/platform/cnss_prealloc/cnss_prealloc.c

@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012,2014-2017,2019-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mempool.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/version.h>
+#include "cnss_common.h"
+#ifdef CONFIG_CNSS_OUT_OF_TREE
+#include "cnss_prealloc.h"
+#else
+#include <net/cnss_prealloc.h>
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
+/* Ideally header should be from standard include path. So this is not an
+ * ideal way of header inclusion but use of slab struct to derive cache
+ * from a mem ptr helps in avoiding additional tracking and/or adding headroom
+ * of 8 bytes for cache in the beginning of buffer and wasting extra memory,
+ * particulary in the case when size of memory requested falls around the edge
+ * of a page boundary. We also have precedence of minidump_memory.c which
+ * includes mm/slab.h using this style.
+ */
+#include "../mm/slab.h"
+#endif
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS prealloc driver");
+
+/* cnss preallocation scheme is a memory pool that always tries to keep a
+ * list of free memory for use in emergencies. It is implemented on kernel
+ * features: memorypool and kmem cache.
+ */
+
+struct cnss_pool {
+	size_t size;
+	int min;
+	const char name[50];
+	mempool_t *mp;
+	struct kmem_cache *cache;
+};
+
+/**
+ * Memory pool
+ * -----------
+ *
+ * How to update this table:
+ *
+ *  1. Add a new row with following elements
+ *      size  : Size of one allocation unit in bytes.
+ *      min   : Minimum units to be reserved. Used only if a regular
+ *              allocation fails.
+ *      name  : Name of the cache/pool. Will be displayed in /proc/slabinfo
+ *              if not merged with another pool.
+ *      mp    : A pointer to memory pool. Updated during init.
+ *      cache : A pointer to cache. Updated during init.
+ * 2. Always keep the table in increasing order
+ * 3. Please keep the reserve pool as minimum as possible as it's always
+ *    preallocated.
+ * 4. Always profile with different use cases after updating this table.
+ * 5. A dynamic view of this pool can be viewed at /proc/slabinfo.
+ * 6. Each pool has a sys node at /sys/kernel/slab/<name>
+ *
+ */
+
+/* size, min pool reserve, name, memorypool handler, cache handler*/
+static struct cnss_pool cnss_pools_default[] = {
+	{8 * 1024, 16, "cnss-pool-8k", NULL, NULL},
+	{16 * 1024, 16, "cnss-pool-16k", NULL, NULL},
+	{32 * 1024, 22, "cnss-pool-32k", NULL, NULL},
+	{64 * 1024, 38, "cnss-pool-64k", NULL, NULL},
+	{128 * 1024, 10, "cnss-pool-128k", NULL, NULL},
+};
+
+static struct cnss_pool cnss_pools_adrastea[] = {
+	{8 * 1024, 2, "cnss-pool-8k", NULL, NULL},
+	{16 * 1024, 10, "cnss-pool-16k", NULL, NULL},
+	{32 * 1024, 8, "cnss-pool-32k", NULL, NULL},
+	{64 * 1024, 4, "cnss-pool-64k", NULL, NULL},
+	{128 * 1024, 2, "cnss-pool-128k", NULL, NULL},
+};
+
+static struct cnss_pool cnss_pools_wcn6750[] = {
+	{8 * 1024, 2, "cnss-pool-8k", NULL, NULL},
+	{16 * 1024, 8, "cnss-pool-16k", NULL, NULL},
+	{32 * 1024, 11, "cnss-pool-32k", NULL, NULL},
+	{64 * 1024, 15, "cnss-pool-64k", NULL, NULL},
+	{128 * 1024, 4, "cnss-pool-128k", NULL, NULL},
+};
+
+struct cnss_pool *cnss_pools;
+unsigned int cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_default);
+
+/**
+ * cnss_pool_alloc_threshold() - Allocation threshold
+ *
+ * Minimum memory size to be part of cnss pool.
+ *
+ * Return: Size
+ *
+ */
+static inline size_t cnss_pool_alloc_threshold(void)
+{
+	return cnss_pools[0].size;
+}
+
+/**
+ * cnss_pool_int() - Initialize memory pools.
+ *
+ * Create cnss pools as configured by cnss_pools[]. It is the responsibility of
+ * the caller to invoke cnss_pool_deinit() routine to clean it up. This
+ * function needs to be called at early boot to preallocate minimum buffers in
+ * the pool.
+ *
+ * Return: 0 - success, otherwise error code.
+ *
+ */
+static int cnss_pool_init(void)
+{
+	int i;
+
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
+		/* Create the slab cache */
+		cnss_pools[i].cache =
+			kmem_cache_create_usercopy(cnss_pools[i].name,
+						   cnss_pools[i].size, 0,
+						   SLAB_ACCOUNT, 0,
+						   cnss_pools[i].size, NULL);
+		if (!cnss_pools[i].cache) {
+			pr_err("cnss_prealloc: cache %s failed\n",
+			       cnss_pools[i].name);
+			continue;
+		}
+
+		/* Create the pool and associate to slab cache */
+		cnss_pools[i].mp =
+		    mempool_create(cnss_pools[i].min, mempool_alloc_slab,
+				   mempool_free_slab, cnss_pools[i].cache);
+
+		if (!cnss_pools[i].mp) {
+			pr_err("cnss_prealloc: mempool %s failed\n",
+			       cnss_pools[i].name);
+			kmem_cache_destroy(cnss_pools[i].cache);
+			cnss_pools[i].cache = NULL;
+			continue;
+		}
+
+		pr_info("cnss_prealloc: created mempool %s of min size %d * %zu\n",
+			cnss_pools[i].name, cnss_pools[i].min,
+			cnss_pools[i].size);
+	}
+
+	return 0;
+}
+
+/**
+ * cnss_pool_deinit() - Free memory pools.
+ *
+ * Free the memory pools and return resources back to the system. It warns
+ * if there is any pending element in memory pool or cache.
+ *
+ */
+static void cnss_pool_deinit(void)
+{
+	int i;
+
+	if (!cnss_pools)
+		return;
+
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
+		pr_info("cnss_prealloc: destroy mempool %s\n",
+			cnss_pools[i].name);
+		mempool_destroy(cnss_pools[i].mp);
+		kmem_cache_destroy(cnss_pools[i].cache);
+		cnss_pools[i].mp = NULL;
+		cnss_pools[i].cache = NULL;
+	}
+}
+
+static void cnss_assign_prealloc_pool(unsigned long device_id)
+{
+	pr_info("cnss_prealloc: assign cnss pool for device id 0x%lx", device_id);
+
+	switch (device_id) {
+	case ADRASTEA_DEVICE_ID:
+		cnss_pools = cnss_pools_adrastea;
+		cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_adrastea);
+		break;
+	case WCN6750_DEVICE_ID:
+		cnss_pools = cnss_pools_wcn6750;
+		cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_wcn6750);
+		break;
+	case WCN6450_DEVICE_ID:
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+	case MANGO_DEVICE_ID:
+	case PEACH_DEVICE_ID:
+	case KIWI_DEVICE_ID:
+	default:
+		cnss_pools = cnss_pools_default;
+		cnss_prealloc_pool_size = ARRAY_SIZE(cnss_pools_default);
+	}
+}
+
+void cnss_initialize_prealloc_pool(unsigned long device_id)
+{
+	cnss_assign_prealloc_pool(device_id);
+	cnss_pool_init();
+}
+EXPORT_SYMBOL(cnss_initialize_prealloc_pool);
+
+void cnss_deinitialize_prealloc_pool(void)
+{
+	cnss_pool_deinit();
+}
+EXPORT_SYMBOL(cnss_deinitialize_prealloc_pool);
+
+/**
+ * cnss_pool_get_index() - Get the index of memory pool
+ * @mem: Allocated memory
+ *
+ * Returns the index of the memory pool which fits the reqested memory. The
+ * complexity of this check is O(num of memory pools). Returns a negative
+ * value with error code in case of failure.
+ *
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
+static int cnss_pool_get_index(void *mem)
+{
+	struct slab *slab;
+	struct kmem_cache *cache;
+	int i;
+
+	if (!virt_addr_valid(mem))
+		return -EINVAL;
+
+	/* mem -> slab -> cache */
+	slab = virt_to_slab(mem);
+	if (!slab)
+		return -ENOENT;
+
+	cache = slab->slab_cache;
+	if (!cache)
+		return -ENOENT;
+
+	/* Check if memory belongs to a pool */
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
+		if (cnss_pools[i].cache == cache)
+			return i;
+	}
+
+	return -ENOENT;
+}
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) */
+static int cnss_pool_get_index(void *mem)
+{
+	struct page *page;
+	struct kmem_cache *cache;
+	int i;
+
+	if (!virt_addr_valid(mem))
+		return -EINVAL;
+
+	/* mem -> page -> cache */
+	page = virt_to_head_page(mem);
+	if (!page)
+		return -ENOENT;
+
+	cache = page->slab_cache;
+	if (!cache)
+		return -ENOENT;
+
+	/* Check if memory belongs to a pool */
+	for (i = 0; i < cnss_prealloc_pool_size; i++) {
+		if (cnss_pools[i].cache == cache)
+			return i;
+	}
+
+	return -ENOENT;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) */
+
+/**
+ * wcnss_prealloc_get() - Get preallocated memory from a pool
+ * @size: Size to allocate
+ *
+ * Memory pool is chosen based on the size. If memory is not available in a
+ * given pool it goes to next higher sized pool until it succeeds.
+ *
+ * Return: A void pointer to allocated memory
+ */
+void *wcnss_prealloc_get(size_t size)
+{
+
+	void *mem = NULL;
+	gfp_t gfp_mask = __GFP_ZERO;
+	int i;
+
+	if (!cnss_pools)
+		return mem;
+
+	if (in_interrupt() || !preemptible() || rcu_preempt_depth())
+		gfp_mask |= GFP_ATOMIC;
+	else
+		gfp_mask |= GFP_KERNEL;
+
+	if (size >= cnss_pool_alloc_threshold()) {
+
+		for (i = 0; i < cnss_prealloc_pool_size; i++) {
+			if (cnss_pools[i].size >= size && cnss_pools[i].mp) {
+				mem = mempool_alloc(cnss_pools[i].mp, gfp_mask);
+				if (mem)
+					break;
+			}
+		}
+	}
+
+	if (!mem && size >= cnss_pool_alloc_threshold()) {
+		pr_debug("cnss_prealloc: not available for size %zu, flag %x\n",
+			 size, gfp_mask);
+	}
+
+	return mem;
+}
+EXPORT_SYMBOL(wcnss_prealloc_get);
+
+/**
+ * wcnss_prealloc_put() - Relase allocated memory
+ * @mem: Allocated memory
+ *
+ * Free the memory got by wcnss_prealloc_get() to slab or pool reserve if memory
+ * pool doesn't have enough elements.
+ *
+ * Return: 1 - success
+ *         0 - fail
+ */
+int wcnss_prealloc_put(void *mem)
+{
+	int i;
+
+	if (!mem || !cnss_pools)
+		return 0;
+
+	i = cnss_pool_get_index(mem);
+	if (i >= 0 && i < cnss_prealloc_pool_size && cnss_pools[i].mp) {
+		mempool_free(mem, cnss_pools[i].mp);
+		return 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(wcnss_prealloc_put);
+
+/* Not implemented. Make use of Linux SLAB features. */
+void wcnss_prealloc_check_memory_leak(void) {}
+EXPORT_SYMBOL(wcnss_prealloc_check_memory_leak);
+
+/* Not implemented. Make use of Linux SLAB features. */
+int wcnss_pre_alloc_reset(void) { return -EOPNOTSUPP; }
+EXPORT_SYMBOL(wcnss_pre_alloc_reset);
+
+/**
+ * cnss_prealloc_is_valid_dt_node_found - Check if valid device tree node
+ *                                        present
+ *
+ * Valid device tree node means a node with "qcom,wlan" property present
+ * and "status" property not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool cnss_prealloc_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_node_with_property(dn, "qcom,wlan") {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+static int __init cnss_prealloc_init(void)
+{
+	if (!cnss_prealloc_is_valid_dt_node_found())
+		return -ENODEV;
+
+	return 0;
+}
+
+static void __exit cnss_prealloc_exit(void)
+{
+	return;
+}
+
+module_init(cnss_prealloc_init);
+module_exit(cnss_prealloc_exit);
+

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/monaco_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/monaco_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/niobe_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/niobe_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/pineapple_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/pineapple_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/pitti_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/pitti_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/sun_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/sun_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/volcano_consolidate_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 2 - 0
qcom/opensource/wlan/platform/cnss_prealloc/volcano_gki_defconfig

@@ -0,0 +1,2 @@
+CONFIG_WCNSS_MEM_PRE_ALLOC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 30 - 0
qcom/opensource/wlan/platform/cnss_utils/Kconfig

@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config CNSS_UTILS
+	tristate "CNSS utilities support"
+	help
+	  Add CNSS utilities support for the WLAN driver module.
+	  This feature enables wlan driver to use CNSS utilities APIs to set
+	  and get wlan related information.
+
+config CNSS_QMI_SVC
+	tristate "CNSS QMI SVC support"
+	help
+	  Add CNSS QMI SVC support for the WLAN driver module.
+	  This feature enable wlan driver to use CNSS QMI service APIs to set
+	  and get wlan related information.
+
+config CNSS_PLAT_IPC_QMI_SVC
+	tristate "CNSS Platform QMI IPC Support"
+	help
+	  Add CNSS platform kernel and user space components IPC using QMI.
+
+config CNSS_OUT_OF_TREE
+	bool "Build module out-of-tree"
+	help
+	  This enables building the module out of the main kernel tree
+
+config FEATURE_SMEM_MAILBOX
+	bool "Enable Feature SMEM Mailbox"
+	default n
+

+ 15 - 0
qcom/opensource/wlan/platform/cnss_utils/Makefile

@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ccflags-y += -Wmissing-prototypes
+
+ifeq ($(CONFIG_CNSS_OUT_OF_TREE),y)
+ccflags-y += -I$(WLAN_PLATFORM_ROOT)/inc
+endif
+
+obj-$(CONFIG_CNSS_UTILS) += cnss_utils.o
+
+obj-$(CONFIG_CNSS_QMI_SVC) += wlan_firmware_service.o
+wlan_firmware_service-y := wlan_firmware_service_v01.o device_management_service_v01.o ip_multimedia_subsystem_private_service_v01.o
+
+obj-$(CONFIG_CNSS_PLAT_IPC_QMI_SVC) += cnss_plat_ipc_qmi_svc.o
+cnss_plat_ipc_qmi_svc-y := cnss_plat_ipc_qmi.o cnss_plat_ipc_service_v01.o

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/anorak_consolidate_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/anorak_gki_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/blair_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/blair_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 25 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_common.h

@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define QCA6174_VENDOR_ID	0x168C
+#define QCA6174_DEVICE_ID	0x003E
+#define QCA6290_VENDOR_ID	0x17CB
+#define QCA6290_DEVICE_ID	0x1100
+#define QCA6390_VENDOR_ID	0x17CB
+#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
+#define MANGO_VENDOR_ID		0x17CB
+#define MANGO_DEVICE_ID		0x110A
+#define PEACH_VENDOR_ID		0x17CB
+#define PEACH_DEVICE_ID		0x110E
+#define WCN6750_DEVICE_ID	0x6750
+#define WCN6450_DEVICE_ID	0x6450
+#define ADRASTEA_DEVICE_ID	0xabcd

+ 988 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_qmi.c

@@ -0,0 +1,988 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/qrtr.h>
+#include <linux/soc/qcom/qmi.h>
+#if IS_ENABLED(CONFIG_IPC_LOGGING)
+#include <linux/ipc_logging.h>
+#endif
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <linux/limits.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include "cnss_plat_ipc_qmi.h"
+#include "cnss_plat_ipc_service_v01.h"
+
+#define CNSS_MAX_FILE_SIZE (32 * 1024 * 1024)
+#define CNSS_PLAT_IPC_MAX_USER 1
+#define CNSS_PLAT_IPC_QMI_FILE_TXN_TIMEOUT 10000
+#define QMI_INIT_RETRY_MAX_TIMES 240
+#define QMI_INIT_RETRY_DELAY_MS 250
+#define NUM_LOG_PAGES			10
+#define CNSS_DAEMON_CFG_WAIT_RETRY	200
+#define CNSS_DAEMON_CFG_WAIT_MS	50
+
+/**
+ * struct cnss_plat_ipc_file_data: File transfer context data
+ * @name: File name
+ * @buf: Buffer provided for TX/RX file contents
+ * @id: File ID corresponding to file name
+ * @buf_size: Buffer size
+ * @file_fize: File Size
+ * @seg_index: Running index for buffer segments
+ * @seg_len: Total number of segments
+ * @end: End of transaction
+ * @complete: Completion variable for file transfer
+ */
+struct cnss_plat_ipc_file_data {
+	char *name;
+	char *buf;
+	u32 id;
+	u32 buf_size;
+	u32 file_size;
+	u32 seg_index;
+	u32 seg_len;
+	u32 end;
+	struct completion complete;
+};
+
+/**
+ * struct cnss_plat_ipc_qmi_client_ctx: Context for QMI IPC client
+ * @client_sq: QMI IPC client QRTR socket
+ * @client_connected: QMI IPC client connection status
+ * @connection_update_cb: Registered user callback for QMI connection status
+ * @cb_ctx: Context for registered user
+ * @num_user: Number of registered users
+ */
+struct cnss_plat_ipc_qmi_client_ctx {
+	struct sockaddr_qrtr client_sq;
+	bool client_connected;
+
+	cnss_plat_ipc_connection_update
+		connection_update_cb[CNSS_PLAT_IPC_MAX_USER];
+	void *cb_ctx[CNSS_PLAT_IPC_MAX_USER];
+	u32 num_user;
+};
+
+/**
+ * struct cnss_plat_ipc_qmi_svc_ctx: Platform context for QMI IPC service
+ * @svc_hdl: QMI server handle
+ * @file_idr: File ID generator
+ * @flle_idr_lock: File ID generator usage lock
+ * @qmi_client_ctx: ontext for QMI IPC client
+ */
+struct cnss_plat_ipc_qmi_svc_ctx {
+	struct qmi_handle *svc_hdl;
+	struct idr file_idr;
+	struct mutex file_idr_lock; /* File ID generator usage lock */
+	struct cnss_plat_ipc_qmi_client_ctx
+		qmi_client_ctx[CNSS_PLAT_IPC_MAX_QMI_CLIENTS + 1];
+};
+
+static struct cnss_plat_ipc_qmi_svc_ctx plat_ipc_qmi_svc;
+static struct cnss_plat_ipc_daemon_config daemon_cfg;
+
+#if IS_ENABLED(CONFIG_IPC_LOGGING)
+static void *cnss_plat_ipc_log_context;
+
+static void cnss_plat_ipc_logging_init(void)
+{
+	cnss_plat_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
+							   "cnss_plat", 0);
+	if (!cnss_plat_ipc_log_context)
+		pr_err("cnss_plat: Unable to create log context\n");
+}
+
+static void cnss_plat_ipc_logging_deinit(void)
+{
+	if (cnss_plat_ipc_log_context) {
+		ipc_log_context_destroy(cnss_plat_ipc_log_context);
+		cnss_plat_ipc_log_context = NULL;
+	}
+}
+
+static void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
+					  const char *log_level, char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list va_args;
+
+	va_start(va_args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &va_args;
+
+	if (log_level)
+		printk("%scnss_plat: %pV", log_level, &vaf);
+
+	ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
+
+	va_end(va_args);
+}
+
+#define cnss_plat_ipc_log_print(_x...) \
+		cnss_plat_ipc_debug_log_print(cnss_plat_ipc_log_context, _x)
+#else
+static void cnss_plat_ipc_logging_init(void) {};
+static void cnss_plat_ipc_logging_deinit(void) {};
+
+static void cnss_plat_ipc_debug_log_print(void *log_ctx, char *process, const char *fn,
+					  const char *log_level, char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list va_args;
+
+	va_start(va_args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &va_args;
+
+	if (log_level)
+		printk("%scnss_plat: %pV", log_level, &vaf);
+
+	va_end(va_args);
+}
+
+#define cnss_plat_ipc_log_print(_x...) \
+		cnss_plat_ipc_debug_log_print((void *)NULL, _x)
+#endif
+
+#define proc_name (in_irq() ? "irq" : \
+		(in_softirq() ? "soft_irq" : current->comm))
+#define cnss_plat_ipc_err(_fmt, ...) \
+		cnss_plat_ipc_log_print(proc_name, __func__, \
+		KERN_ERR, _fmt, ##__VA_ARGS__)
+
+#define cnss_plat_ipc_info(_fmt, ...) \
+		cnss_plat_ipc_log_print(proc_name, __func__, \
+		KERN_INFO, _fmt, ##__VA_ARGS__)
+
+#define cnss_plat_ipc_dbg(_fmt, ...) \
+		cnss_plat_ipc_log_print(proc_name, __func__, \
+		KERN_DEBUG, _fmt, ##__VA_ARGS__)
+/**
+ * cnss_plat_ipc_init_file_data() - Initialize file transfer context data
+ * @name: File name
+ * @buf: Buffer pointer for file contents
+ * @buf_size: Buffer size for download / upload
+ * @file_size: File size for upload
+ *
+ * Return: File data pointer
+ */
+static
+struct cnss_plat_ipc_file_data *cnss_plat_ipc_init_file_data(char *name,
+							     char *buf,
+							     u32 buf_size,
+							     u32 file_size)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_file_data *fd;
+
+	fd = kmalloc(sizeof(*fd), GFP_KERNEL);
+	if (!fd)
+		goto end;
+	fd->name = name;
+	fd->buf = buf;
+	fd->buf_size = buf_size;
+	fd->file_size = file_size;
+	fd->seg_index = 0;
+	fd->end = 0;
+	if (file_size)
+		fd->seg_len =
+			(file_size / CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01) +
+			!!(file_size % CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01);
+	else
+		fd->seg_len = 0;
+	init_completion(&fd->complete);
+	mutex_lock(&svc->file_idr_lock);
+	fd->id = idr_alloc_cyclic(&svc->file_idr, fd, 0, U32_MAX, GFP_KERNEL);
+	if (fd->id < 0) {
+		kfree(fd);
+		fd = NULL;
+	}
+	mutex_unlock(&svc->file_idr_lock);
+end:
+	return fd;
+}
+
+/**
+ * cnss_plat_ipc_deinit_file_data() - Release file transfer context data
+ * @fd: File data pointer
+ *
+ * Return: 0 on success, negative error values otherwise
+ */
+static int cnss_plat_ipc_deinit_file_data(struct cnss_plat_ipc_file_data *fd)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	int ret = 0;
+
+	if (unlikely(!fd))
+		return -EINVAL;
+
+	mutex_lock(&svc->file_idr_lock);
+	idr_remove(&svc->file_idr, fd->id);
+	mutex_unlock(&svc->file_idr_lock);
+
+	if (!fd->end)
+		ret = -EINVAL;
+	kfree(fd);
+	return ret;
+}
+
+/**
+ * cnss_plat_ipc_qmi_update_user() - Inform registered users about QMI
+ *                                      client status
+ * @client_id: User space QMI IPC client ID. Also works as
+ *		array index for QMI client context
+ *
+ * Return: None
+ */
+static void
+cnss_plat_ipc_qmi_update_user(enum cnss_plat_ipc_qmi_client_id_v01 client_id)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client =
+			&svc->qmi_client_ctx[client_id];
+	int i;
+
+	for (i = 0; i < qmi_client->num_user; i++) {
+		if (qmi_client->connection_update_cb[i])
+			qmi_client->connection_update_cb[i]
+						(qmi_client->cb_ctx[i],
+						qmi_client->client_connected);
+	}
+}
+
+/**
+ * cnss_plat_ipc_qmi_file_upload() - Upload data as platform accessible file
+ * @client_id: User space QMI IPC client ID. Also works as
+ *		array index for QMI client context
+ * @file_mame: File name to store in platform data location
+ * @file_buf: Pointer to buffer with file contents
+ * @file_size: Provides the size of buffer / file size
+ *
+ * Return: 0 on success, negative error values otherwise
+ */
+int cnss_plat_ipc_qmi_file_upload(enum cnss_plat_ipc_qmi_client_id_v01
+				  client_id, char *file_name, u8 *file_buf,
+				  u32 file_size)
+{
+	struct cnss_plat_ipc_qmi_file_upload_ind_msg_v01 ind;
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client;
+	int ret;
+	struct cnss_plat_ipc_file_data *fd;
+
+	if (client_id > CNSS_PLAT_IPC_MAX_QMI_CLIENTS) {
+		cnss_plat_ipc_err("Invalid Client ID: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	qmi_client = &svc->qmi_client_ctx[client_id];
+
+	if (!qmi_client->client_connected || !file_name || !file_buf)
+		return -EINVAL;
+
+	cnss_plat_ipc_info("File name: %s Size: %d\n", file_name, file_size);
+
+	if (file_size == 0 || file_size > CNSS_MAX_FILE_SIZE)
+		return -EINVAL;
+
+	fd = cnss_plat_ipc_init_file_data(file_name, file_buf, file_size,
+					  file_size);
+	if (!fd) {
+		cnss_plat_ipc_err("Unable to initialize file transfer data\n");
+		return -EINVAL;
+	}
+	scnprintf(ind.file_name, CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01, "%s",
+		  fd->name);
+	ind.file_size = fd->file_size;
+	ind.file_id = fd->id;
+
+	ret = qmi_send_indication
+			(svc->svc_hdl, &qmi_client->client_sq,
+			 CNSS_PLAT_IPC_QMI_FILE_UPLOAD_IND_V01,
+			 CNSS_PLAT_IPC_QMI_FILE_UPLOAD_IND_MSG_V01_MAX_MSG_LEN,
+			 cnss_plat_ipc_qmi_file_upload_ind_msg_v01_ei, &ind);
+
+	if (ret < 0) {
+		cnss_plat_ipc_err("QMI failed: %d\n", ret);
+		goto end;
+	}
+	ret = wait_for_completion_timeout(&fd->complete,
+					  msecs_to_jiffies
+					  (CNSS_PLAT_IPC_QMI_FILE_TXN_TIMEOUT));
+	if (!ret)
+		cnss_plat_ipc_err("Timeout Uploading file: %s\n", fd->name);
+
+end:
+	ret = cnss_plat_ipc_deinit_file_data(fd);
+	cnss_plat_ipc_dbg("Status: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_upload);
+
+/**
+ * cnss_plat_ipc_qmi_file_upload_req_handler() - QMI Upload data request handler
+ * @handle: Pointer to QMI handle
+ * @sq: QMI socket
+ * @txn: QMI transaction pointer
+ * @decoded_msg: Pointer to decoded QMI message
+ *
+ * Handles the QMI upload sequence from userspace. It uses the file descriptor
+ * ID to upload buffer contents to QMI messages as segments.
+ *
+ * Return: None
+ */
+static void
+cnss_plat_ipc_qmi_file_upload_req_handler(struct qmi_handle *handle,
+					  struct sockaddr_qrtr *sq,
+					  struct qmi_txn *txn,
+					  const void *decoded_msg)
+{
+	struct cnss_plat_ipc_qmi_file_upload_req_msg_v01 *req_msg;
+	struct cnss_plat_ipc_qmi_file_upload_resp_msg_v01 *resp;
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	int ret = 0;
+	struct cnss_plat_ipc_file_data *fd;
+
+	req_msg = (struct cnss_plat_ipc_qmi_file_upload_req_msg_v01 *)
+		   decoded_msg;
+	if (!req_msg)
+		return;
+	cnss_plat_ipc_dbg("File ID: %d Seg Index: %d\n", req_msg->file_id,
+			  req_msg->seg_index);
+
+	mutex_lock(&svc->file_idr_lock);
+	fd = idr_find(&svc->file_idr, req_msg->file_id);
+	mutex_unlock(&svc->file_idr_lock);
+	if (!fd) {
+		cnss_plat_ipc_err("Invalid File ID %d\n", req_msg->file_id);
+		return;
+	}
+
+	if (req_msg->seg_index != fd->seg_index) {
+		cnss_plat_ipc_err("File %s transfer segment failure\n", fd->name);
+		complete(&fd->complete);
+	}
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp)
+		return;
+
+	resp->file_id = fd->id;
+	resp->seg_index = fd->seg_index++;
+	resp->seg_buf_len =
+		(fd->buf_size > CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01 ?
+		 CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01 : fd->buf_size);
+	resp->end = (fd->seg_index == fd->seg_len);
+	memcpy(resp->seg_buf, fd->buf, resp->seg_buf_len);
+
+	cnss_plat_ipc_dbg("ID: %d Seg ID: %d Len: %d End: %d\n", resp->file_id,
+			  resp->seg_index, resp->seg_buf_len, resp->end);
+
+	ret = qmi_send_response
+		(svc->svc_hdl, sq, txn,
+		CNSS_PLAT_IPC_QMI_FILE_UPLOAD_RESP_V01,
+		CNSS_PLAT_IPC_QMI_FILE_UPLOAD_RESP_MSG_V01_MAX_MSG_LEN,
+		cnss_plat_ipc_qmi_file_upload_resp_msg_v01_ei,
+		resp);
+
+	if (ret < 0) {
+		cnss_plat_ipc_err("QMI failed: %d\n", ret);
+		goto end;
+	}
+
+	fd->buf_size -= resp->seg_buf_len;
+	fd->buf += resp->seg_buf_len;
+	if (resp->end) {
+		fd->end = true;
+		complete(&fd->complete);
+	}
+end:
+	kfree(resp);
+}
+
+/**
+ * cnss_plat_ipc_qmi_file_download() - Download platform accessible file
+ * @client_id: User space QMI IPC client ID. Also works as
+ *		array index for QMI client context
+ * @file_mame: File name to get from platform data location
+ * @buf: Pointer of the buffer to store file contents
+ * @size: Provides the size of buffer. It is updated to reflect the file size
+ *        at the end of file download.
+ */
+int cnss_plat_ipc_qmi_file_download(enum cnss_plat_ipc_qmi_client_id_v01
+				    client_id, char *file_name, char *buf,
+				    u32 *size)
+{
+	struct cnss_plat_ipc_qmi_file_download_ind_msg_v01 ind;
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client;
+	int ret;
+	struct cnss_plat_ipc_file_data *fd;
+
+	if (client_id > CNSS_PLAT_IPC_MAX_QMI_CLIENTS) {
+		cnss_plat_ipc_err("Invalid Client ID: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	qmi_client = &svc->qmi_client_ctx[client_id];
+
+	if (!qmi_client->client_connected || !file_name || !buf)
+		return -EINVAL;
+
+	fd = cnss_plat_ipc_init_file_data(file_name, buf, *size, 0);
+	if (!fd) {
+		cnss_plat_ipc_err("Unable to initialize file transfer data\n");
+		return -EINVAL;
+	}
+
+	scnprintf(ind.file_name, CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01, "%s",
+		  file_name);
+	ind.file_id = fd->id;
+
+	ret = qmi_send_indication
+		(svc->svc_hdl, &qmi_client->client_sq,
+		 CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_IND_V01,
+		 CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN,
+		 cnss_plat_ipc_qmi_file_download_ind_msg_v01_ei, &ind);
+
+	if (ret < 0) {
+		cnss_plat_ipc_err("QMI failed: %d\n", ret);
+		goto end;
+	}
+	ret = wait_for_completion_timeout(&fd->complete,
+					  msecs_to_jiffies
+					  (CNSS_PLAT_IPC_QMI_FILE_TXN_TIMEOUT));
+	if (!ret)
+		cnss_plat_ipc_err("Timeout downloading file:%s\n", fd->name);
+
+end:
+	*size = fd->file_size;
+	ret = cnss_plat_ipc_deinit_file_data(fd);
+	cnss_plat_ipc_dbg("Status: %d Size: %d\n", ret, *size);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_download);
+
+/**
+ * cnss_plat_ipc_qmi_file_download_req_handler() - QMI download request handler
+ * @handle: Pointer to QMI handle
+ * @sq: QMI socket
+ * @txn: QMI transaction pointer
+ * @decoded_msg: Pointer to decoded QMI message
+ *
+ * Handles the QMI download request sequence to userspace. It uses the file
+ * descriptor ID to download QMI message buffer segment to file descriptor
+ * buffer.
+ *
+ * Return: None
+ */
+static void
+cnss_plat_ipc_qmi_file_download_req_handler(struct qmi_handle *handle,
+					    struct sockaddr_qrtr *sq,
+					    struct qmi_txn *txn,
+					    const void *decoded_msg)
+{
+	struct cnss_plat_ipc_qmi_file_download_req_msg_v01 *req_msg;
+	struct cnss_plat_ipc_qmi_file_download_resp_msg_v01 resp = {0};
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	int ret = 0;
+	struct cnss_plat_ipc_file_data *fd;
+
+	req_msg = (struct cnss_plat_ipc_qmi_file_download_req_msg_v01 *)
+		   decoded_msg;
+	if (!req_msg)
+		return;
+	cnss_plat_ipc_dbg("File ID: %d Size: %d Seg Len: %d Index: %d End: %d\n",
+			  req_msg->file_id, req_msg->file_size,
+			  req_msg->seg_buf_len, req_msg->seg_index,
+			  req_msg->end);
+
+	mutex_lock(&svc->file_idr_lock);
+	fd = idr_find(&svc->file_idr, req_msg->file_id);
+	mutex_unlock(&svc->file_idr_lock);
+	if (!fd) {
+		cnss_plat_ipc_err("Invalid File ID: %d\n", req_msg->file_id);
+		return;
+	}
+
+	if (req_msg->file_size > fd->buf_size) {
+		cnss_plat_ipc_err("File %s size %d larger than buffer size %d\n",
+				  fd->name, req_msg->file_size, fd->buf_size);
+		goto file_error;
+	}
+	if (req_msg->seg_buf_len > CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01 ||
+	    ((req_msg->seg_buf_len + fd->file_size) > fd->buf_size)) {
+		cnss_plat_ipc_err("Segment buf ID: %d buffer size %d not allowed\n",
+				  req_msg->seg_index, req_msg->seg_buf_len);
+		goto file_error;
+	}
+	if (req_msg->seg_index != fd->seg_index) {
+		cnss_plat_ipc_err("File %s transfer segment failure\n",
+				  fd->name);
+		goto file_error;
+	}
+
+	memcpy(fd->buf, req_msg->seg_buf, req_msg->seg_buf_len);
+	fd->seg_index++;
+	fd->buf += req_msg->seg_buf_len;
+	fd->file_size += req_msg->seg_buf_len;
+
+	resp.file_id = fd->id;
+	resp.seg_index = fd->seg_index;
+	ret = qmi_send_response
+		(svc->svc_hdl, sq, txn,
+		CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_RESP_V01,
+		CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN,
+		cnss_plat_ipc_qmi_file_download_resp_msg_v01_ei,
+		&resp);
+
+	if (ret < 0)
+		cnss_plat_ipc_err("QMI failed: %d\n", ret);
+
+	if (req_msg->end) {
+		fd->end = true;
+		complete(&fd->complete);
+	}
+
+	return;
+file_error:
+	complete(&fd->complete);
+}
+
+/**
+ * cnss_plat_ipc_qmi_init_setup_req_handler() - Init_Setup QMI message handler
+ * @handle: Pointer to QMI handle
+ * @sq: QMI socket
+ * @txn: QMI transaction pointer
+ * @decoded_msg: Pointer to decoded QMI message
+ *
+ * Handles the QMI Init setup handshake message from userspace.
+ * buffer.
+ *
+ * Return: None
+ */
+static void
+cnss_plat_ipc_qmi_init_setup_req_handler(struct qmi_handle *handle,
+					 struct sockaddr_qrtr *sq,
+					 struct qmi_txn *txn,
+					 const void *decoded_msg)
+{
+	struct cnss_plat_ipc_qmi_init_setup_req_msg_v01 *req_msg;
+	struct cnss_plat_ipc_qmi_init_setup_resp_msg_v01 resp = {0};
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_daemon_config *cfg = &daemon_cfg;
+	int ret = 0;
+
+	req_msg =
+		(struct cnss_plat_ipc_qmi_init_setup_req_msg_v01 *)decoded_msg;
+	cnss_plat_ipc_dbg("MAC: %d HW_TRC: %d CAL: %d\n",
+			  req_msg->dms_mac_addr_supported,
+			  req_msg->qdss_hw_trace_override,
+			  req_msg->cal_file_available_bitmask);
+
+	cfg->dms_mac_addr_supported = req_msg->dms_mac_addr_supported;
+	cfg->qdss_hw_trace_override = req_msg->qdss_hw_trace_override;
+	cfg->cal_file_available_bitmask = req_msg->cal_file_available_bitmask;
+	cfg->initialized = 1;
+
+	ret = qmi_send_response
+		(svc->svc_hdl, sq, txn,
+		 CNSS_PLAT_IPC_QMI_INIT_SETUP_RESP_V01,
+		 CNSS_PLAT_IPC_QMI_INIT_SETUP_RESP_MSG_V01_MAX_MSG_LEN,
+		 cnss_plat_ipc_qmi_init_setup_resp_msg_v01_ei, &resp);
+	if (ret < 0)
+		cnss_plat_ipc_err("%s: QMI failed: %d\n", __func__, ret);
+}
+
+/**
+ * cnss_plat_ipc_qmi_reg_client_req_handler() - Register QMI client
+ * @handle: Pointer to QMI handle
+ * @sq: QMI socket
+ * @txn: QMI transaction pointer
+ * @decoded_msg: Pointer to decoded QMI message
+ *
+ * Handles the userspace QMI client registration.
+ *
+ * Return: None
+ */
+static void
+cnss_plat_ipc_qmi_reg_client_req_handler(struct qmi_handle *handle,
+					 struct sockaddr_qrtr *sq,
+					 struct qmi_txn *txn,
+					 const void *decoded_msg)
+{
+	struct cnss_plat_ipc_qmi_reg_client_req_msg_v01 *req_msg;
+	struct cnss_plat_ipc_qmi_reg_client_resp_msg_v01 resp = {0};
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client = svc->qmi_client_ctx;
+	int ret = 0;
+
+	req_msg =
+		(struct cnss_plat_ipc_qmi_reg_client_req_msg_v01 *)decoded_msg;
+
+	if (req_msg->client_id_valid) {
+		if (req_msg->client_id <= CNSS_PLAT_IPC_MAX_QMI_CLIENTS &&
+		    !qmi_client[req_msg->client_id].client_connected) {
+			cnss_plat_ipc_info
+				("%s: QMI Client Connected. QMI Socket Node: %d Port: %d ID: %d\n",
+				 __func__, sq->sq_node, sq->sq_port,
+				 req_msg->client_id);
+			qmi_client[req_msg->client_id].client_sq = *sq;
+			qmi_client[req_msg->client_id].client_connected = true;
+			cnss_plat_ipc_qmi_update_user
+					((enum cnss_plat_ipc_qmi_client_id_v01)
+					req_msg->client_id);
+		} else {
+			cnss_plat_ipc_err("QMI client already connected or Invalid client id\n");
+			return;
+		}
+	}
+
+	ret = qmi_send_response
+		(svc->svc_hdl, sq, txn,
+		 CNSS_PLAT_IPC_QMI_REG_CLIENT_RESP_V01,
+		 CNSS_PLAT_IPC_QMI_REG_CLIENT_RESP_MSG_V01_MAX_MSG_LEN,
+		 cnss_plat_ipc_qmi_reg_client_resp_msg_v01_ei, &resp);
+
+	if (ret < 0)
+		cnss_plat_ipc_err("QMI failed: %d\n", ret);
+}
+
+/**
+ * cnss_plat_ipc_qmi_disconnect_cb() - Handler for QMI node disconnect specific
+ *                                     to node and port
+ * @handle: Pointer to QMI handle
+ * @node: QMI node that is disconnected
+ * @port: QMI port that is disconnected
+ *
+ * Return: None
+ */
+static void cnss_plat_ipc_qmi_disconnect_cb(struct qmi_handle *handle,
+					    unsigned int node,
+					    unsigned int port)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client =
+					svc->qmi_client_ctx;
+	struct cnss_plat_ipc_file_data *fd;
+	u32 file_id;
+	int i;
+
+	if (svc->svc_hdl != handle) {
+		cnss_plat_ipc_err("Invalid QMI Handle\n");
+		return;
+	}
+
+	for (i = 0; i <= CNSS_PLAT_IPC_MAX_QMI_CLIENTS; i++) {
+		if (qmi_client[i].client_connected &&
+		    qmi_client[i].client_sq.sq_node == node &&
+		    qmi_client[i].client_sq.sq_port == port) {
+			cnss_plat_ipc_err
+				("%s: QMI client disconnect. QMI Socket Node:%d Port:%d ID: %d\n",
+				 __func__, node, port, i);
+			qmi_client[i].client_sq.sq_node = 0;
+			qmi_client[i].client_sq.sq_port = 0;
+			qmi_client[i].client_sq.sq_family = 0;
+			qmi_client[i].client_connected = false;
+
+			/* Daemon killed. Fail any download / upload in progress. This
+			 * will also free stale fd
+			 */
+			mutex_lock(&svc->file_idr_lock);
+			idr_for_each_entry(&svc->file_idr, fd, file_id)
+				complete(&fd->complete);
+			mutex_unlock(&svc->file_idr_lock);
+			cnss_plat_ipc_qmi_update_user(i);
+		}
+	}
+}
+
+/**
+ * cnss_plat_ipc_qmi_bye_cb() - Handler for QMI node disconnect for all port of
+ *                              the given node.
+ * @handle: Pointer to QMI handle
+ * @node: QMI node that is disconnected
+ *
+ * Return: None
+ */
+static void cnss_plat_ipc_qmi_bye_cb(struct qmi_handle *handle,
+				     unsigned int node)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client =
+					svc->qmi_client_ctx;
+	int i;
+
+	for (i = 0; i <= CNSS_PLAT_IPC_MAX_QMI_CLIENTS; i++) {
+		cnss_plat_ipc_qmi_disconnect_cb
+					(handle, node,
+					 qmi_client[i].client_sq.sq_port);
+	}
+}
+
+static struct qmi_ops cnss_plat_ipc_qmi_ops = {
+	/* inform a client that all clients from a node are gone */
+	.bye = cnss_plat_ipc_qmi_bye_cb,
+	.del_client = cnss_plat_ipc_qmi_disconnect_cb,
+};
+
+static struct qmi_msg_handler cnss_plat_ipc_qmi_req_handlers[] = {
+	{
+		.type = QMI_REQUEST,
+		.msg_id = CNSS_PLAT_IPC_QMI_REG_CLIENT_REQ_V01,
+		.ei = cnss_plat_ipc_qmi_reg_client_req_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct cnss_plat_ipc_qmi_reg_client_req_msg_v01),
+		.fn = cnss_plat_ipc_qmi_reg_client_req_handler,
+	},
+	{
+		.type = QMI_REQUEST,
+		.msg_id = CNSS_PLAT_IPC_QMI_INIT_SETUP_REQ_V01,
+		.ei = cnss_plat_ipc_qmi_init_setup_req_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct cnss_plat_ipc_qmi_init_setup_req_msg_v01),
+		.fn = cnss_plat_ipc_qmi_init_setup_req_handler,
+	},
+	{
+		.type = QMI_REQUEST,
+		.msg_id = CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_REQ_V01,
+		.ei = cnss_plat_ipc_qmi_file_download_req_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct cnss_plat_ipc_qmi_file_download_req_msg_v01),
+		.fn = cnss_plat_ipc_qmi_file_download_req_handler,
+	},
+	{
+		.type = QMI_REQUEST,
+		.msg_id = CNSS_PLAT_IPC_QMI_FILE_UPLOAD_REQ_V01,
+		.ei = cnss_plat_ipc_qmi_file_upload_req_msg_v01_ei,
+		.decoded_size =
+		sizeof(struct cnss_plat_ipc_qmi_file_upload_req_msg_v01),
+		.fn = cnss_plat_ipc_qmi_file_upload_req_handler,
+	},
+	{}
+};
+
+/**
+ * cnss_plat_ipc_qmi_daemon_config() - Get daemon config for CNSS platform
+ *
+ * Return: Pointer to daemon client config
+ */
+struct cnss_plat_ipc_daemon_config *cnss_plat_ipc_qmi_daemon_config(void)
+{
+	int i;
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client =
+		&svc->qmi_client_ctx[CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01];
+
+	if (!qmi_client->client_connected)
+		return NULL;
+
+	for (i = 0; i < CNSS_DAEMON_CFG_WAIT_RETRY; i++) {
+		if (daemon_cfg.initialized == 1)
+			break;
+
+		msleep(CNSS_DAEMON_CFG_WAIT_MS);
+	}
+
+	return &daemon_cfg;
+}
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_daemon_config);
+
+/**
+ * cnss_plat_ipc_register() - Register for QMI IPC client status update
+ * @client_id: User space QMI IPC client ID. Also works as
+ *		array index for QMI client context
+ * @connect_update_cb: Function pointer for callback
+ * @cb_ctx: Callback context
+ *
+ * Return: 0 on success, negative error value otherwise
+ */
+int cnss_plat_ipc_register(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			   cnss_plat_ipc_connection_update
+			   connection_update_cb, void *cb_ctx)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client;
+	int num_user;
+
+	if (client_id > CNSS_PLAT_IPC_MAX_QMI_CLIENTS) {
+		cnss_plat_ipc_err("Invalid Client ID: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	qmi_client = &svc->qmi_client_ctx[client_id];
+	num_user = qmi_client->num_user;
+
+	if (num_user >= CNSS_PLAT_IPC_MAX_USER) {
+		cnss_plat_ipc_err("Max Service users reached\n");
+		return -EINVAL;
+	}
+
+	qmi_client->connection_update_cb[num_user] = connection_update_cb;
+	qmi_client->cb_ctx[num_user] = cb_ctx;
+	qmi_client->num_user++;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_plat_ipc_register);
+
+/**
+ * cnss_plat_ipc_unregister() - Unregister QMI IPC client status callback
+ * @client_id: User space QMI IPC client ID. Also works as
+ *		array index for QMI client context
+ * @cb_cbt: Callback context provided during registration
+ *
+ * Return: None
+ */
+void cnss_plat_ipc_unregister(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			      void *cb_ctx)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+	struct cnss_plat_ipc_qmi_client_ctx *qmi_client;
+	int i;
+
+	if (client_id > CNSS_PLAT_IPC_MAX_QMI_CLIENTS) {
+		cnss_plat_ipc_err("Invalid Client ID: %d\n", client_id);
+		return;
+	}
+
+	qmi_client = &svc->qmi_client_ctx[client_id];
+
+	for (i = 0; i < qmi_client->num_user; i++) {
+		if (qmi_client->cb_ctx[i] == cb_ctx) {
+			qmi_client->cb_ctx[i] = NULL;
+			qmi_client->connection_update_cb[i] = NULL;
+			qmi_client->num_user--;
+			break;
+		}
+	}
+}
+EXPORT_SYMBOL(cnss_plat_ipc_unregister);
+
+/**
+ * cnss_plat_ipc_init_fn() - CNSS Platform qmi service init function
+ *
+ * Initialize a QMI client handle and register new QMI service for CNSS Platform
+ *
+ * Return: None
+ */
+static void cnss_plat_ipc_init_fn(struct work_struct *work)
+{
+	int ret = 0, retry = 0;
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+
+	svc->svc_hdl = kzalloc(sizeof(*svc->svc_hdl), GFP_KERNEL);
+	if (!svc->svc_hdl)
+		return;
+
+retry:
+	ret = qmi_handle_init(svc->svc_hdl,
+			      CNSS_PLAT_IPC_QMI_MAX_MSG_SIZE_V01,
+			      &cnss_plat_ipc_qmi_ops,
+			      cnss_plat_ipc_qmi_req_handlers);
+	if (ret < 0) {
+		/* If QMI fails to init, retry for total
+		 * QMI_INIT_RETRY_DELAY_MS * QMI_INIT_RETRY_MAX_TIMES ms.
+		 */
+		if (retry++ < QMI_INIT_RETRY_MAX_TIMES) {
+			msleep(QMI_INIT_RETRY_DELAY_MS);
+			goto retry;
+		}
+		cnss_plat_ipc_err("Failed to init QMI handle after %d ms * %d, err = %d\n",
+				  QMI_INIT_RETRY_DELAY_MS,
+				  QMI_INIT_RETRY_MAX_TIMES, ret);
+		goto free_svc_hdl;
+	}
+
+	ret = qmi_add_server(svc->svc_hdl,
+			     CNSS_PLATFORM_SERVICE_ID_V01,
+			     CNSS_PLATFORM_SERVICE_VERS_V01, 0);
+	if (ret < 0) {
+		cnss_plat_ipc_err("Server add fail: %d\n", ret);
+		goto release_svc_hdl;
+	}
+
+	cnss_plat_ipc_info("CNSS Platform IPC QMI Service is started\n");
+	idr_init(&svc->file_idr);
+	mutex_init(&svc->file_idr_lock);
+	return;
+
+release_svc_hdl:
+	qmi_handle_release(svc->svc_hdl);
+free_svc_hdl:
+	kfree(svc->svc_hdl);
+}
+
+/**
+ * cnss_plat_ipc_is_valid_dt_node_found - Check if valid device tree node
+ *                                        present
+ *
+ * Valid device tree node means a node with "qcom,wlan" property present
+ * and "status" property not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool cnss_plat_ipc_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_node_with_property(dn, "qcom,wlan") {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+static DECLARE_WORK(cnss_plat_ipc_init_work, cnss_plat_ipc_init_fn);
+
+static int __init cnss_plat_ipc_qmi_svc_init(void)
+{
+	if (!cnss_plat_ipc_is_valid_dt_node_found())
+		return -ENODEV;
+
+	/* Schedule a work to do real init to avoid blocking here */
+	cnss_plat_ipc_logging_init();
+	schedule_work(&cnss_plat_ipc_init_work);
+	return 0;
+}
+
+/**
+ * cnss_plat_ipc_qmi_svc_exit() - CNSS Platform qmi service exit
+ *
+ * Release all resources during exit
+ *
+ * Return: None
+ */
+static void __exit cnss_plat_ipc_qmi_svc_exit(void)
+{
+	struct cnss_plat_ipc_qmi_svc_ctx *svc = &plat_ipc_qmi_svc;
+
+	cancel_work_sync(&cnss_plat_ipc_init_work);
+
+	if (svc->svc_hdl) {
+		qmi_handle_release(svc->svc_hdl);
+		kfree(svc->svc_hdl);
+		idr_destroy(&svc->file_idr);
+	}
+
+	cnss_plat_ipc_logging_deinit();
+}
+
+module_init(cnss_plat_ipc_qmi_svc_init);
+module_exit(cnss_plat_ipc_qmi_svc_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Platform IPC QMI Service");

+ 90 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_qmi.h

@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _CNSS_PLAT_IPC_QMI_H
+#define _CNSS_PLAT_IPC_QMI_H
+
+#include "cnss_plat_ipc_service_v01.h"
+
+/* As the value of CNSS_PLAT_IPC_MAX_QMI_CLIENTS will keep changing
+ * addition of new QMI client, it cannot be kept in IDL as change in
+ * existing value can cause backward compatibily issue. Keep it here
+ * and update its value with new QMI client ID added in enum in IDL.
+ */
+#define CNSS_PLAT_IPC_MAX_QMI_CLIENTS CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01
+
+/**
+ * cnss_plat_ipc_daemon_config: Config options provided by cnss-daemon
+ * @initialized: Set when daemon configs are initialized
+ * @dms_mac_addr_supported: DMS MAC address provisioning support
+ * @qdss_hw_trace_override: QDSS config for HW trace enable
+ * @cal_file_available_bitmask: Calibration file available
+ */
+struct cnss_plat_ipc_daemon_config {
+	u8 initialized;
+	u8 dms_mac_addr_supported;
+	u8 qdss_hw_trace_override;
+	u32 cal_file_available_bitmask;
+};
+
+typedef void (*cnss_plat_ipc_connection_update)(void *cb_ctx,
+						bool connection_status);
+
+/**
+ * Persistent caldb file store which is a runtime FW param based feature will
+ * fail if CONFIG_CNSS_PLAT_IPC_QMI_SVC  is not enabled.
+ **/
+#if IS_ENABLED(CONFIG_CNSS_PLAT_IPC_QMI_SVC)
+int cnss_plat_ipc_register(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			   cnss_plat_ipc_connection_update
+			   connection_update_cb, void *cb_ctx);
+void cnss_plat_ipc_unregister(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			      void *cb_ctx);
+int cnss_plat_ipc_qmi_file_download(enum cnss_plat_ipc_qmi_client_id_v01
+				    client_id, char *file_name, char *buf,
+				    u32 *size);
+int cnss_plat_ipc_qmi_file_upload(enum cnss_plat_ipc_qmi_client_id_v01
+				  client_id, char *file_name, u8 *file_buf,
+				  u32 file_size);
+struct cnss_plat_ipc_daemon_config *cnss_plat_ipc_qmi_daemon_config(void);
+#else
+static inline
+int cnss_plat_ipc_register(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			   cnss_plat_ipc_connection_update
+			   connection_update_cb, void *cb_ctx)
+{
+	return 0;
+}
+
+static inline
+void cnss_plat_ipc_unregister(enum cnss_plat_ipc_qmi_client_id_v01 client_id,
+			      void *cb_ctx)
+{
+}
+
+static inline
+int cnss_plat_ipc_qmi_file_download(enum cnss_plat_ipc_qmi_client_id_v01
+				    client_id, char *file_name, char *buf,
+				    u32 *size)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline
+int cnss_plat_ipc_qmi_file_upload(enum cnss_plat_ipc_qmi_client_id_v01
+				  client_id, char *file_name, u8 *file_buf,
+				  u32 file_size)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline
+struct cnss_plat_ipc_daemon_config *cnss_plat_ipc_qmi_daemon_config(void)
+{
+	return NULL;
+}
+
+#endif
+#endif

+ 402 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_service_v01.c

@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2021, The Linux Foundation. All rights reserved. */
+
+#include "cnss_plat_ipc_service_v01.h"
+#include <linux/module.h>
+
+struct qmi_elem_info cnss_plat_ipc_qmi_init_setup_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_init_setup_req_msg_v01,
+					   dms_mac_addr_supported),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_init_setup_req_msg_v01,
+					   qdss_hw_trace_override),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_init_setup_req_msg_v01,
+					   cal_file_available_bitmask),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_init_setup_req_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_init_setup_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
+					   cnss_plat_ipc_qmi_init_setup_resp_msg_v01,
+					   resp),
+		.ei_array      = qmi_response_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_init_setup_resp_msg_v01,
+					   drv_status),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_init_setup_resp_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_download_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_ind_msg_v01,
+					   file_name),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_ind_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_download_ind_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_download_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   file_size),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x04,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   seg_index),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x05,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   seg_buf_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x05,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_req_msg_v01,
+					   seg_buf),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_download_req_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_download_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
+					   cnss_plat_ipc_qmi_file_download_resp_msg_v01,
+					   resp),
+		.ei_array      = qmi_response_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_resp_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x04,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_download_resp_msg_v01,
+					   seg_index),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_download_resp_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_ind_msg_v01,
+					   file_name),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_ind_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_ind_msg_v01,
+					   file_size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_upload_ind_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_req_msg_v01,
+					   seg_index),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_upload_req_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_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
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   resp),
+		.ei_array      = qmi_response_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x04,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x05,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   seg_index),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x06,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   seg_buf_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x06,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_file_upload_resp_msg_v01,
+					   seg_buf),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_file_upload_resp_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_reg_client_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
+					   cnss_plat_ipc_qmi_reg_client_req_msg_v01,
+					   client_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum cnss_plat_ipc_qmi_client_id_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   cnss_plat_ipc_qmi_reg_client_req_msg_v01,
+					   client_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(cnss_plat_ipc_qmi_reg_client_req_msg_v01_ei);
+
+struct qmi_elem_info cnss_plat_ipc_qmi_reg_client_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
+					   cnss_plat_ipc_qmi_reg_client_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(cnss_plat_ipc_qmi_reg_client_resp_msg_v01_ei);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("WLAN FW QMI service");

+ 127 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_plat_ipc_service_v01.h

@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
+
+#ifndef CNSS_PLAT_IPC_SERVICE_V01_H
+#define CNSS_PLAT_IPC_SERVICE_V01_H
+
+#include <linux/soc/qcom/qmi.h>
+
+#define CNSS_PLATFORM_SERVICE_ID_V01 0x42E
+#define CNSS_PLATFORM_SERVICE_VERS_V01 0x01
+
+#define CNSS_PLAT_IPC_QMI_REG_CLIENT_RESP_V01 0x0006
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_REQ_V01 0x0003
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_IND_V01 0x0004
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_IND_V01 0x0002
+#define CNSS_PLAT_IPC_QMI_REG_CLIENT_REQ_V01 0x0006
+#define CNSS_PLAT_IPC_QMI_INIT_SETUP_REQ_V01 0x0001
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_REQ_V01 0x0005
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_RESP_V01 0x0003
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_RESP_V01 0x0005
+#define CNSS_PLAT_IPC_QMI_INIT_SETUP_RESP_V01 0x0001
+
+#define CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01 32
+#define CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01 61440
+#define CNSS_PLAT_IPC_QMI_MAX_MSG_SIZE_V01 65535
+
+#define CNSS_PLAT_IPC_QMI_DRIVER_CBC_DONE_V01 ((u64)0x01ULL)
+#define CNSS_PLAT_IPC_QMI_DRIVER_WLAN_ACTIVE_V01 ((u64)0x02ULL)
+
+enum cnss_plat_ipc_qmi_client_id_v01 {
+	CNSS_PLAT_IPC_QMI_CLIENT_ID_MIN_VAL_V01 = INT_MIN,
+	CNSS_PLAT_IPC_BT_QMI_CLIENT_V01 = 0,
+	CNSS_PLAT_IPC_DAEMON_QMI_CLIENT_V01 = 1,
+	CNSS_PLAT_IPC_QMI_CLIENT_ID_MAX_VAL_V01 = INT_MAX,
+};
+
+struct cnss_plat_ipc_qmi_init_setup_req_msg_v01 {
+	u8 dms_mac_addr_supported;
+	u8 qdss_hw_trace_override;
+	u32 cal_file_available_bitmask;
+};
+
+#define CNSS_PLAT_IPC_QMI_INIT_SETUP_REQ_MSG_V01_MAX_MSG_LEN 15
+extern struct qmi_elem_info cnss_plat_ipc_qmi_init_setup_req_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_init_setup_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u64 drv_status;
+};
+
+#define CNSS_PLAT_IPC_QMI_INIT_SETUP_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info cnss_plat_ipc_qmi_init_setup_resp_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_download_ind_msg_v01 {
+	char file_name[CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01 + 1];
+	u32 file_id;
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 42
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_download_ind_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_download_req_msg_v01 {
+	u32 file_id;
+	u32 file_size;
+	u8 end;
+	u32 seg_index;
+	u32 seg_buf_len;
+	u8 seg_buf[CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01];
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 61470
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_download_req_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u32 file_id;
+	u32 seg_index;
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_download_resp_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_upload_ind_msg_v01 {
+	char file_name[CNSS_PLAT_IPC_QMI_MAX_FILE_NAME_LEN_V01 + 1];
+	u32 file_id;
+	u32 file_size;
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_IND_MSG_V01_MAX_MSG_LEN 49
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_ind_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_upload_req_msg_v01 {
+	u32 file_id;
+	u32 seg_index;
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_req_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_file_upload_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u32 file_id;
+	u8 end;
+	u32 seg_index;
+	u32 seg_buf_len;
+	u8 seg_buf[CNSS_PLAT_IPC_QMI_MAX_DATA_SIZE_V01];
+};
+
+#define CNSS_PLAT_IPC_QMI_FILE_UPLOAD_RESP_MSG_V01_MAX_MSG_LEN 61470
+extern struct qmi_elem_info cnss_plat_ipc_qmi_file_upload_resp_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_reg_client_req_msg_v01 {
+	u8 client_id_valid;
+	enum cnss_plat_ipc_qmi_client_id_v01 client_id;
+};
+
+#define CNSS_PLAT_IPC_QMI_REG_CLIENT_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info cnss_plat_ipc_qmi_reg_client_req_msg_v01_ei[];
+
+struct cnss_plat_ipc_qmi_reg_client_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define CNSS_PLAT_IPC_QMI_REG_CLIENT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info cnss_plat_ipc_qmi_reg_client_resp_msg_v01_ei[];
+
+#endif

+ 590 - 0
qcom/opensource/wlan/platform/cnss_utils/cnss_utils.c

@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017, 2019, 2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "cnss_utils: " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#ifdef CONFIG_CNSS_OUT_OF_TREE
+#include "cnss_utils.h"
+#else
+#include <net/cnss_utils.h>
+#endif
+
+#ifdef CONFIG_FEATURE_SMEM_MAILBOX
+#include <smem-mailbox.h>
+#endif
+
+#define CNSS_MAX_CH_NUM 157
+struct cnss_unsafe_channel_list {
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+};
+
+struct cnss_dfs_nol_info {
+	void *dfs_nol_info;
+	u16 dfs_nol_info_len;
+};
+
+#define MAX_NO_OF_MAC_ADDR 4
+#define MAC_PREFIX_LEN 2
+struct cnss_wlan_mac_addr {
+	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+	u32 no_of_mac_addr_set;
+};
+
+enum mac_type {
+	CNSS_MAC_PROVISIONED,
+	CNSS_MAC_DERIVED,
+};
+
+static struct cnss_utils_priv {
+	struct cnss_unsafe_channel_list unsafe_channel_list;
+	struct cnss_dfs_nol_info dfs_nol_info;
+	/* generic mutex for unsafe channel */
+	struct mutex unsafe_channel_list_lock;
+	/* generic spin-lock for dfs_nol info */
+	spinlock_t dfs_nol_info_lock;
+	int driver_load_cnt;
+	struct cnss_wlan_mac_addr wlan_mac_addr;
+	struct cnss_wlan_mac_addr wlan_der_mac_addr;
+	enum cnss_utils_cc_src cc_source;
+	struct dentry *root_dentry;
+	/* generic mutex for device_id */
+	struct mutex cnss_device_id_lock;
+	enum cnss_utils_device_type cnss_device_type;
+#ifdef CONFIG_FEATURE_SMEM_MAILBOX
+	bool smem_mailbox_initialized;
+	int smem_mailbox_id;
+#endif
+} *cnss_utils_priv;
+
+int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
+				       u16 *unsafe_ch_list, u16 ch_count)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	mutex_lock(&priv->unsafe_channel_list_lock);
+	if (!unsafe_ch_list || ch_count > CNSS_MAX_CH_NUM) {
+		mutex_unlock(&priv->unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	priv->unsafe_channel_list.unsafe_ch_count = ch_count;
+
+	if (ch_count == 0)
+		goto end;
+
+	memcpy(priv->unsafe_channel_list.unsafe_ch_list,
+	       unsafe_ch_list, ch_count * sizeof(u16));
+
+end:
+	mutex_unlock(&priv->unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_utils_set_wlan_unsafe_channel);
+
+int cnss_utils_get_wlan_unsafe_channel(struct device *dev,
+				       u16 *unsafe_ch_list,
+				       u16 *ch_count, u16 buf_len)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	mutex_lock(&priv->unsafe_channel_list_lock);
+	if (!unsafe_ch_list || !ch_count) {
+		mutex_unlock(&priv->unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	if (buf_len <
+	    (priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+		mutex_unlock(&priv->unsafe_channel_list_lock);
+		return -ENOMEM;
+	}
+
+	*ch_count = priv->unsafe_channel_list.unsafe_ch_count;
+	memcpy(unsafe_ch_list, priv->unsafe_channel_list.unsafe_ch_list,
+	       priv->unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+	mutex_unlock(&priv->unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_utils_get_wlan_unsafe_channel);
+
+enum cnss_utils_device_type cnss_utils_update_device_type(
+			enum cnss_utils_device_type  device_type)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	mutex_lock(&priv->cnss_device_id_lock);
+	pr_info("cnss_utils: device type:%d\n", device_type);
+	if (priv->cnss_device_type == CNSS_UNSUPPORETD_DEVICE_TYPE) {
+		priv->cnss_device_type = device_type;
+		pr_info("cnss_utils: set device type:%d\n",
+			priv->cnss_device_type);
+	} else {
+		pr_info("cnss_utils: device type already set :%d\n",
+			priv->cnss_device_type);
+	}
+	mutex_unlock(&priv->cnss_device_id_lock);
+	return priv->cnss_device_type;
+}
+EXPORT_SYMBOL(cnss_utils_update_device_type);
+
+int cnss_utils_wlan_set_dfs_nol(struct device *dev,
+				const void *info, u16 info_len)
+{
+	void *temp;
+	void *old_nol_info;
+	struct cnss_dfs_nol_info *dfs_info;
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	if (!info || !info_len)
+		return -EINVAL;
+
+	temp = kmemdup(info, info_len, GFP_ATOMIC);
+	if (!temp)
+		return -ENOMEM;
+
+	spin_lock_bh(&priv->dfs_nol_info_lock);
+	dfs_info = &priv->dfs_nol_info;
+	old_nol_info = dfs_info->dfs_nol_info;
+	dfs_info->dfs_nol_info = temp;
+	dfs_info->dfs_nol_info_len = info_len;
+	spin_unlock_bh(&priv->dfs_nol_info_lock);
+	kfree(old_nol_info);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_utils_wlan_set_dfs_nol);
+
+int cnss_utils_wlan_get_dfs_nol(struct device *dev,
+				void *info, u16 info_len)
+{
+	int len;
+	struct cnss_dfs_nol_info *dfs_info;
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	if (!info || !info_len)
+		return -EINVAL;
+
+	spin_lock_bh(&priv->dfs_nol_info_lock);
+
+	dfs_info = &priv->dfs_nol_info;
+	if (!dfs_info->dfs_nol_info ||
+	    dfs_info->dfs_nol_info_len == 0) {
+		spin_unlock_bh(&priv->dfs_nol_info_lock);
+		return -ENOENT;
+	}
+
+	len = min(info_len, dfs_info->dfs_nol_info_len);
+	memcpy(info, dfs_info->dfs_nol_info, len);
+	spin_unlock_bh(&priv->dfs_nol_info_lock);
+
+	return len;
+}
+EXPORT_SYMBOL(cnss_utils_wlan_get_dfs_nol);
+
+void cnss_utils_increment_driver_load_cnt(struct device *dev)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return;
+
+	++(priv->driver_load_cnt);
+}
+EXPORT_SYMBOL(cnss_utils_increment_driver_load_cnt);
+
+int cnss_utils_get_driver_load_cnt(struct device *dev)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	return priv->driver_load_cnt;
+}
+EXPORT_SYMBOL(cnss_utils_get_driver_load_cnt);
+
+static int set_wlan_mac_address(const u8 *mac_list, const uint32_t len,
+				enum mac_type type)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+	u32 no_of_mac_addr;
+	struct cnss_wlan_mac_addr *addr = NULL;
+	int iter;
+	u8 *temp = NULL;
+
+	if (!priv)
+		return -EINVAL;
+
+	if (len == 0 || (len % ETH_ALEN) != 0) {
+		pr_err("Invalid length %d\n", len);
+		return -EINVAL;
+	}
+
+	no_of_mac_addr = len / ETH_ALEN;
+	if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
+		pr_err("Exceed maximum supported MAC address %u %u\n",
+		       MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
+		return -EINVAL;
+	}
+
+	if (type == CNSS_MAC_PROVISIONED)
+		addr = &priv->wlan_mac_addr;
+	else
+		addr = &priv->wlan_der_mac_addr;
+
+	if (addr->no_of_mac_addr_set) {
+		pr_err("WLAN MAC address is already set, num %d type %d\n",
+		       addr->no_of_mac_addr_set, type);
+		return 0;
+	}
+
+	addr->no_of_mac_addr_set = no_of_mac_addr;
+	temp = &addr->mac_addr[0][0];
+
+	for (iter = 0; iter < no_of_mac_addr;
+	     ++iter, temp += ETH_ALEN, mac_list += ETH_ALEN) {
+		ether_addr_copy(temp, mac_list);
+		pr_debug("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+			 temp[0], temp[1], temp[2],
+			 temp[3], temp[4], temp[5]);
+	}
+	return 0;
+}
+
+int cnss_utils_set_wlan_mac_address(const u8 *mac_list, const uint32_t len)
+{
+	return set_wlan_mac_address(mac_list, len, CNSS_MAC_PROVISIONED);
+}
+EXPORT_SYMBOL(cnss_utils_set_wlan_mac_address);
+
+int cnss_utils_set_wlan_derived_mac_address(const u8 *mac_list,
+					    const uint32_t len)
+{
+	return set_wlan_mac_address(mac_list, len, CNSS_MAC_DERIVED);
+}
+EXPORT_SYMBOL(cnss_utils_set_wlan_derived_mac_address);
+
+static u8 *get_wlan_mac_address(struct device *dev,
+				u32 *num, enum mac_type type)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!priv)
+		goto out;
+
+	if (type == CNSS_MAC_PROVISIONED)
+		addr = &priv->wlan_mac_addr;
+	else
+		addr = &priv->wlan_der_mac_addr;
+
+	if (!addr->no_of_mac_addr_set) {
+		pr_err("WLAN MAC address is not set, type %d\n", type);
+		goto out;
+	}
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+
+out:
+	*num = 0;
+	return NULL;
+}
+
+u8 *cnss_utils_get_wlan_mac_address(struct device *dev, uint32_t *num)
+{
+	return get_wlan_mac_address(dev, num, CNSS_MAC_PROVISIONED);
+}
+EXPORT_SYMBOL(cnss_utils_get_wlan_mac_address);
+
+u8 *cnss_utils_get_wlan_derived_mac_address(struct device *dev,
+					    uint32_t *num)
+{
+	return get_wlan_mac_address(dev, num, CNSS_MAC_DERIVED);
+}
+EXPORT_SYMBOL(cnss_utils_get_wlan_derived_mac_address);
+
+void cnss_utils_set_cc_source(struct device *dev,
+			      enum cnss_utils_cc_src cc_source)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return;
+
+	priv->cc_source = cc_source;
+}
+EXPORT_SYMBOL(cnss_utils_set_cc_source);
+
+enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+
+	return priv->cc_source;
+}
+EXPORT_SYMBOL(cnss_utils_get_cc_source);
+
+#ifdef CONFIG_FEATURE_SMEM_MAILBOX
+int cnss_utils_smem_mailbox_write(struct device *dev, int flags,
+				  const __u8 *data, uint32_t len)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	if (!priv)
+		return -EINVAL;
+	if (!priv->smem_mailbox_initialized) {
+		if (smem_mailbox_start(priv->smem_mailbox_id, NULL) != 1) {
+			pr_err("Didn't init smem mailbox properly\n");
+			return -EINVAL;
+		} else
+			priv->smem_mailbox_initialized = true;
+	}
+	return smem_mailbox_write(priv->smem_mailbox_id, flags, (__u8 *)data,
+				  len);
+}
+EXPORT_SYMBOL(cnss_utils_smem_mailbox_write);
+#endif
+
+static ssize_t cnss_utils_mac_write(struct file *fp,
+				    const char __user *user_buf,
+				    size_t count, loff_t *off)
+{
+	struct cnss_utils_priv *priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[128];
+	char *input, *mac_type, *mac_address;
+	u8 *dest_mac;
+	u8 val;
+	const char *delim = "\n";
+	size_t len = 0;
+	char temp[3] = "";
+
+	len = min_t(size_t, count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+	buf[len] = '\0';
+
+	input = buf;
+
+	mac_type = strsep(&input, delim);
+	if (!mac_type)
+		return -EINVAL;
+	if (!input)
+		return -EINVAL;
+
+	mac_address = strsep(&input, delim);
+	if (!mac_address)
+		return -EINVAL;
+	if (strcmp("0x", mac_address)) {
+		pr_err("Invalid MAC prefix\n");
+		return -EINVAL;
+	}
+
+	len = strlen(mac_address);
+	mac_address += MAC_PREFIX_LEN;
+	len -= MAC_PREFIX_LEN;
+	if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
+	    len % (ETH_ALEN * 2) != 0) {
+		pr_err("Invalid MAC address length %zu\n", len);
+		return -EINVAL;
+	}
+
+	if (!strcmp("provisioned", mac_type)) {
+		dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
+		priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
+	} else if (!strcmp("derived", mac_type)) {
+		dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
+		priv->wlan_der_mac_addr.no_of_mac_addr_set =
+			len / (ETH_ALEN * 2);
+	} else {
+		pr_err("Invalid MAC address type %s\n", mac_type);
+		return -EINVAL;
+	}
+
+	while (len--) {
+		temp[0] = *mac_address++;
+		temp[1] = *mac_address++;
+		if (kstrtou8(temp, 16, &val))
+			return -EINVAL;
+		*dest_mac++ = val;
+	}
+	return count;
+}
+
+static int cnss_utils_mac_show(struct seq_file *s, void *data)
+{
+	u8 mac[6];
+	int i;
+	struct cnss_utils_priv *priv = s->private;
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	addr = &priv->wlan_mac_addr;
+	if (addr->no_of_mac_addr_set) {
+		seq_puts(s, "\nProvisioned MAC addresseses\n");
+		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+			ether_addr_copy(mac, addr->mac_addr[i]);
+			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+				   mac[0], mac[1], mac[2],
+				   mac[3], mac[4], mac[5]);
+		}
+	}
+
+	addr = &priv->wlan_der_mac_addr;
+	if (addr->no_of_mac_addr_set) {
+		seq_puts(s, "\nDerived MAC addresseses\n");
+		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+			ether_addr_copy(mac, addr->mac_addr[i]);
+			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+				   mac[0], mac[1], mac[2],
+				   mac[3], mac[4], mac[5]);
+		}
+	}
+
+	return 0;
+}
+
+static int cnss_utils_mac_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_utils_mac_show, inode->i_private);
+}
+
+static const struct file_operations cnss_utils_mac_fops = {
+	.read		= seq_read,
+	.write		= cnss_utils_mac_write,
+	.release	= single_release,
+	.open		= cnss_utils_mac_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
+{
+	int ret = 0;
+	struct dentry *root_dentry;
+
+	root_dentry = debugfs_create_dir("cnss_utils", NULL);
+
+	if (IS_ERR(root_dentry)) {
+		ret = PTR_ERR(root_dentry);
+		pr_err("Unable to create debugfs %d\n", ret);
+		goto out;
+	}
+	priv->root_dentry = root_dentry;
+	debugfs_create_file("mac_address", 0600, root_dentry, priv,
+			    &cnss_utils_mac_fops);
+out:
+	return ret;
+}
+
+/**
+ * cnss_utils_is_valid_dt_node_found - Check if valid device tree node present
+ *
+ * Valid device tree node means a node with "qcom,wlan" property present and
+ * "status" property not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool cnss_utils_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_node_with_property(dn, "qcom,wlan") {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+#ifdef CONFIG_FEATURE_SMEM_MAILBOX
+static void cnss_utils_smem_mailbox_init(void)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	priv->smem_mailbox_id = 0;
+	priv->smem_mailbox_initialized = false;
+}
+
+static void cnss_utils_smem_mailbox_deinit(void)
+{
+	struct cnss_utils_priv *priv = cnss_utils_priv;
+
+	smem_mailbox_stop(priv->smem_mailbox_id);
+}
+#else
+static void cnss_utils_smem_mailbox_init(void)
+{
+}
+
+static void cnss_utils_smem_mailbox_deinit(void)
+{
+}
+#endif
+
+static int __init cnss_utils_init(void)
+{
+	struct cnss_utils_priv *priv = NULL;
+
+	if (!cnss_utils_is_valid_dt_node_found())
+		return -ENODEV;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->cc_source = CNSS_UTILS_SOURCE_CORE;
+	priv->cnss_device_type = CNSS_UNSUPPORETD_DEVICE_TYPE;
+
+	mutex_init(&priv->unsafe_channel_list_lock);
+	mutex_init(&priv->cnss_device_id_lock);
+	spin_lock_init(&priv->dfs_nol_info_lock);
+	cnss_utils_debugfs_create(priv);
+	cnss_utils_priv = priv;
+	cnss_utils_smem_mailbox_init();
+	return 0;
+}
+
+static void __exit cnss_utils_exit(void)
+{
+	cnss_utils_smem_mailbox_deinit();
+	kfree(cnss_utils_priv);
+	cnss_utils_priv = NULL;
+}
+
+module_init(cnss_utils_init);
+module_exit(cnss_utils_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Utilities Driver");

+ 75 - 0
qcom/opensource/wlan/platform/cnss_utils/device_management_service_v01.c

@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
+
+#include <linux/soc/qcom/qmi.h>
+
+#include "device_management_service_v01.h"
+
+struct qmi_elem_info dms_get_mac_address_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum dms_device_mac_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   dms_get_mac_address_req_msg_v01,
+					   device),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(dms_get_mac_address_req_msg_v01_ei);
+
+struct qmi_elem_info dms_get_mac_address_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
+					   dms_get_mac_address_resp_msg_v01,
+					   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
+					   dms_get_mac_address_resp_msg_v01,
+					   mac_address_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   dms_get_mac_address_resp_msg_v01,
+					   mac_address_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_DMS_MAC_ADDR_MAX_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   dms_get_mac_address_resp_msg_v01,
+					   mac_address),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(dms_get_mac_address_resp_msg_v01_ei);

+ 38 - 0
qcom/opensource/wlan/platform/cnss_utils/device_management_service_v01.h

@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
+
+#ifndef DEVICE_MANAGEMENT_SERVICE_V01_H
+#define DEVICE_MANAGEMENT_SERVICE_V01_H
+
+#define DMS_SERVICE_ID_V01 0x02
+#define DMS_SERVICE_VERS_V01 0x01
+
+#define QMI_DMS_GET_MAC_ADDRESS_RESP_V01 0x005C
+#define QMI_DMS_GET_MAC_ADDRESS_REQ_V01 0x005C
+#define QMI_DMS_MAC_ADDR_MAX_V01 8
+
+enum dms_device_mac_enum_v01 {
+	DMS_DEVICE_MAC_ENUM_MIN_VAL_V01 = INT_MIN,
+	DMS_DEVICE_MAC_WLAN_V01 = 0,
+	DMS_DEVICE_MAC_BT_V01 = 1,
+	DMS_DEVICE_MAC_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+struct dms_get_mac_address_req_msg_v01 {
+	enum dms_device_mac_enum_v01 device;
+};
+
+#define DMS_GET_MAC_ADDRESS_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info dms_get_mac_address_req_msg_v01_ei[];
+
+struct dms_get_mac_address_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 mac_address_valid;
+	u32 mac_address_len;
+	u8 mac_address[QMI_DMS_MAC_ADDR_MAX_V01];
+};
+
+#define DMS_GET_MAC_ADDRESS_RESP_MSG_V01_MAX_MSG_LEN 19
+extern struct qmi_elem_info dms_get_mac_address_resp_msg_v01_ei[];
+
+#endif

+ 457 - 0
qcom/opensource/wlan/platform/cnss_utils/ip_multimedia_subsystem_private_service_v01.c

@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "ip_multimedia_subsystem_private_service_v01.h"
+
+static struct qmi_elem_info ims_private_service_header_value_v01_ei[] = {
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = IMS_PRIVATE_SERVICE_HEADER_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         =
+		offsetof(struct ims_private_service_header_value_v01, header),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = IMS_PRIVATE_SERVICE_HEADER_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         =
+		offsetof(struct ims_private_service_header_value_v01, value),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct qmi_elem_info
+ims_private_service_subscribe_ind_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
+		ims_private_service_subscribe_for_indications_req_msg_v01,
+				mt_invite_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+		ims_private_service_subscribe_for_indications_req_msg_v01,
+				mt_invite),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+		ims_private_service_subscribe_for_indications_req_msg_v01,
+				wfc_call_status_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+		ims_private_service_subscribe_for_indications_req_msg_v01,
+				wfc_call_status),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(ims_private_service_subscribe_ind_req_msg_v01_ei);
+
+struct qmi_elem_info
+ims_private_service_subscribe_ind_rsp_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
+		ims_private_service_subscribe_for_indications_rsp_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(ims_private_service_subscribe_ind_rsp_msg_v01_ei);
+
+struct qmi_elem_info ims_private_service_mt_invite_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum ims_subscription_type_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 subscription_type),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 iccid_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = IMS_PRIVATE_SERVICE_MAX_ICCID_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 iccid),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 header_value_list_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 header_value_list_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = IMS_PRIVATE_SERVICE_MAX_MT_INVITE_HEADERS_V01,
+		.elem_size      =
+		sizeof(struct ims_private_service_header_value_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct ims_private_service_mt_invite_ind_msg_v01,
+			 header_value_list),
+		.ei_array      = ims_private_service_header_value_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(ims_private_service_mt_invite_ind_msg_v01_ei);
+
+struct qmi_elem_info ims_private_service_wfc_call_status_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 wfc_call_active),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 all_wfc_calls_held_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 all_wfc_calls_held),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 is_wfc_emergency_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 is_wfc_emergency),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 twt_ims_start_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 twt_ims_start),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 twt_ims_int_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 twt_ims_int),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 media_quality_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wfc_media_quality_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         =
+		offsetof(struct ims_private_service_wfc_call_status_ind_msg_v01,
+			 media_quality),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(ims_private_service_wfc_call_status_ind_msg_v01_ei);
+
+struct qmi_elem_info
+ims_private_service_wfc_call_twt_config_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
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_start_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_start),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_int_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_int),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_upo_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_upo),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_sp_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_sp),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_dl_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_dl),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_config_changed_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         =
+		offsetof(struct
+			 ims_private_service_wfc_call_twt_config_req_msg_v01,
+			 twt_sta_config_changed),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(ims_private_service_wfc_call_twt_config_req_msg_v01_ei);
+
+struct qmi_elem_info
+ims_private_service_wfc_call_twt_config_rsp_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
+			 ims_private_service_wfc_call_twt_config_rsp_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(ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei);

+ 136 - 0
qcom/opensource/wlan/platform/cnss_utils/ip_multimedia_subsystem_private_service_v01.h

@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef IP_MULTIMEDIA_SUBSYSTEM_PRIVATE_SERVICE_V01_H
+#define IP_MULTIMEDIA_SUBSYSTEM_PRIVATE_SERVICE_V01_H
+
+#include <linux/soc/qcom/qmi.h>
+
+#define IMSPRIVATE_SERVICE_ID_V01 0x4D
+#define IMSPRIVATE_SERVICE_VERS_V01 0x01
+
+#define QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_RSP_V01 0x003E
+#define QMI_IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_V01 0x0040
+#define QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01 0x003E
+#define QMI_IMS_PRIVATE_SERVICE_MT_INVITE_IND_V01 0x003F
+#define QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_RSP_V01 0x0041
+#define QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_V01 0x0041
+
+#define IMS_PRIVATE_SERVICE_MAX_MT_INVITE_HEADERS_V01 15
+#define IMS_PRIVATE_SERVICE_HEADER_STR_LEN_V01 1024
+#define IMS_PRIVATE_SERVICE_MAX_ICCID_LEN_V01 21
+
+enum ims_common_resp_enum_v01 {
+	IMS_COMMON_RESP_ENUM_MIN_VAL_V01 = INT_MIN,
+	IMS_COMMON_MSG_NO_ERR_V01 = 0,
+	IMS_COMMON_MSG_IMS_NOT_READY_V01 = 1,
+	IMS_COMMON_MSG_FILE_NOT_AVAILABLE_V01 = 2,
+	IMS_COMMON_MSG_READ_FAILED_V01 = 3,
+	IMS_COMMON_MSG_WRITE_FAILED_V01 = 4,
+	IMS_COMMON_MSG_OTHER_INTERNAL_ERR_V01 = 5,
+	IMS_COMMON_RESP_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum ims_subscription_type_enum_v01 {
+	IMS_SUBSCRIPTION_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+	IMS_SUBSCRIPTION_TYPE_NONE_V01 = -1,
+	IMS_SUBSCRIPTION_TYPE_PRIMARY_V01 = 0,
+	IMS_SUBSCRIPTION_TYPE_SECONDARY_V01 = 1,
+	IMS_SUBSCRIPTION_TYPE_TERTIARY_V01 = 2,
+	IMS_SUBSCRIPTION_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wfc_media_quality_v01 {
+	WFC_MEDIA_QUALITY_MIN_VAL_V01 = INT_MIN,
+	WFC_MEDIA_QUAL_NOT_AVAILABLE_V01 = 0,
+	WFC_MEDIA_QUAL_BAD_V01 = 1,
+	WFC_MEDIA_QUAL_GOOD_V01 = 2,
+	WFC_MEDIA_QUAL_EXCELLENT_V01 = 3,
+	WFC_MEDIA_QUALITY_MAX_VAL_V01 = INT_MAX,
+};
+
+struct ims_private_service_header_value_v01 {
+	char header[IMS_PRIVATE_SERVICE_HEADER_STR_LEN_V01 + 1];
+	char value[IMS_PRIVATE_SERVICE_HEADER_STR_LEN_V01 + 1];
+};
+
+struct ims_private_service_subscribe_for_indications_req_msg_v01 {
+	u8 mt_invite_valid;
+	u8 mt_invite;
+	u8 wfc_call_status_valid;
+	u8 wfc_call_status;
+};
+
+#define IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_MSG_V01_MAX_MSG_LEN 8
+extern struct qmi_elem_info
+ims_private_service_subscribe_ind_req_msg_v01_ei[];
+
+struct ims_private_service_subscribe_for_indications_rsp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_RSP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info
+ims_private_service_subscribe_ind_rsp_msg_v01_ei[];
+
+struct ims_private_service_mt_invite_ind_msg_v01 {
+	enum ims_subscription_type_enum_v01 subscription_type;
+	u8 iccid_valid;
+	char iccid[IMS_PRIVATE_SERVICE_MAX_ICCID_LEN_V01 + 1];
+	u8 header_value_list_valid;
+	u32 header_value_list_len;
+	struct ims_private_service_header_value_v01
+	header_value_list[IMS_PRIVATE_SERVICE_MAX_MT_INVITE_HEADERS_V01];
+};
+
+#define IMS_PRIVATE_SERVICE_MT_INVITE_IND_MSG_V01_MAX_MSG_LEN 30815
+extern struct qmi_elem_info ims_private_service_mt_invite_ind_msg_v01_ei[];
+
+struct ims_private_service_wfc_call_status_ind_msg_v01 {
+	u8 wfc_call_active;
+	u8 all_wfc_calls_held_valid;
+	u8 all_wfc_calls_held;
+	u8 is_wfc_emergency_valid;
+	u8 is_wfc_emergency;
+	u8 twt_ims_start_valid;
+	u64 twt_ims_start;
+	u8 twt_ims_int_valid;
+	u16 twt_ims_int;
+	u8 media_quality_valid;
+	enum wfc_media_quality_v01 media_quality;
+};
+
+#define IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_MSG_V01_MAX_MSG_LEN 35
+extern struct qmi_elem_info
+ims_private_service_wfc_call_status_ind_msg_v01_ei[];
+
+struct ims_private_service_wfc_call_twt_config_req_msg_v01 {
+	u8 twt_sta_start_valid;
+	u64 twt_sta_start;
+	u8 twt_sta_int_valid;
+	u16 twt_sta_int;
+	u8 twt_sta_upo_valid;
+	u16 twt_sta_upo;
+	u8 twt_sta_sp_valid;
+	u16 twt_sta_sp;
+	u8 twt_sta_dl_valid;
+	u16 twt_sta_dl;
+	u8 twt_sta_config_changed_valid;
+	u8 twt_sta_config_changed;
+};
+
+#define IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_MSG_V01_MAX_MSG_LEN 35
+extern struct qmi_elem_info
+ims_private_service_wfc_call_twt_config_req_msg_v01_ei[];
+
+struct ims_private_service_wfc_call_twt_config_rsp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_RSP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info
+ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei[];
+
+#endif

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/monaco_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/monaco_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/niobe_consolidate_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/niobe_gki_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/pineapple_consolidate_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/pineapple_gki_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/pitti_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/pitti_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/sun_consolidate_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 4 - 0
qcom/opensource/wlan/platform/cnss_utils/sun_gki_defconfig

@@ -0,0 +1,4 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_PLAT_IPC_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/volcano_consolidate_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 3 - 0
qcom/opensource/wlan/platform/cnss_utils/volcano_gki_defconfig

@@ -0,0 +1,3 @@
+CONFIG_CNSS_UTILS=m
+CONFIG_CNSS_QMI_SVC=m
+CONFIG_CNSS_OUT_OF_TREE=y

+ 7140 - 0
qcom/opensource/wlan/platform/cnss_utils/wlan_firmware_service_v01.c

@@ -0,0 +1,7140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+
+#include "wlan_firmware_service_v01.h"
+#include <linux/module.h>
+#include <linux/of.h>
+
+static struct qmi_elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_tgt_pipe_cfg_s_v01,
+					   pipe_num),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pipedir_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_tgt_pipe_cfg_s_v01,
+					   pipe_dir),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_tgt_pipe_cfg_s_v01,
+					   nentries),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_tgt_pipe_cfg_s_v01,
+					   nbytes_max),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_tgt_pipe_cfg_s_v01,
+					   flags),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_svc_pipe_cfg_s_v01,
+					   service_id),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pipedir_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_svc_pipe_cfg_s_v01,
+					   pipe_dir),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_ce_svc_pipe_cfg_s_v01,
+					   pipe_num),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_shadow_reg_cfg_s_v01,
+					   id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_shadow_reg_cfg_s_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_shadow_reg_v2_cfg_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_rri_over_ddr_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_rri_over_ddr_cfg_s_v01,
+					   base_addr_low),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_rri_over_ddr_cfg_s_v01,
+					   base_addr_high),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_msi_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_msi_cfg_s_v01,
+					   ce_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_msi_cfg_s_v01,
+					   msi_vector),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_memory_region_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_memory_region_info_s_v01,
+					   region_addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_memory_region_info_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_memory_region_info_s_v01,
+					   secure_flag),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_mem_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_cfg_s_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_cfg_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_cfg_s_v01,
+					   secure_flag),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_mem_seg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_mem_type_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_s_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_s_v01,
+					   mem_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_CFG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_s_v01,
+					   mem_cfg),
+		.ei_array      = wlfw_mem_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_mem_seg_resp_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_resp_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_resp_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_mem_type_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_resp_s_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_mem_seg_resp_s_v01,
+					   restore),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_rf_chip_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_rf_chip_info_s_v01,
+					   chip_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_rf_chip_info_s_v01,
+					   chip_family),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_rf_board_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_rf_board_info_s_v01,
+					   board_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_soc_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_soc_info_s_v01,
+					   soc_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_fw_version_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_fw_version_info_s_v01,
+					   fw_version),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_fw_version_info_s_v01,
+					   fw_build_timestamp),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_host_ddr_range_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_host_ddr_range_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_host_ddr_range_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_m3_segment_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_m3_segment_type_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_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_m3_segment_info_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_m3_segment_info_s_v01,
+					   name),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_dev_mem_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_dev_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_dev_mem_info_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info mlo_chip_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_info_s_v01,
+					   chip_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_info_s_v01,
+					   num_local_links),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_info_s_v01,
+					   hw_link_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_info_s_v01,
+					   valid_mlo_link_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info mlo_chip_v2_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct mlo_chip_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_v2_info_s_v01,
+					   mlo_chip_info),
+		.ei_array      = mlo_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_v2_info_s_v01,
+					   adj_mlo_num_chips),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_ADJ_CHIP_V01,
+		.elem_size      = sizeof(struct mlo_chip_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   mlo_chip_v2_info_s_v01,
+					   adj_mlo_chip_info),
+		.ei_array      = mlo_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_pmu_param_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_PMU_PIN_NAME_MAX_LEN_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_param_v01,
+					   pin_name),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_param_v01,
+					   wake_volt_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_param_v01,
+					   wake_volt),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_param_v01,
+					   sleep_volt_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_param_v01,
+					   sleep_volt),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_pmu_cfg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_cfg_v01,
+					   pmu_param_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_PMU_PARAMS_MAX_V01,
+		.elem_size      = sizeof(struct wlfw_pmu_param_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_pmu_cfg_v01,
+					   pmu_param),
+		.ei_array      = wlfw_pmu_param_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlfw_shadow_reg_v3_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_shadow_reg_v3_cfg_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+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,
+	},
+};
+
+static struct qmi_elem_info wlfw_host_pcie_link_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_host_pcie_link_info_s_v01,
+					   pci_link_speed),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlfw_host_pcie_link_info_s_v01,
+					   pci_link_width),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct qmi_elem_info wlchip_serial_id_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlchip_serial_id_v01,
+					   serial_id_msb),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct
+					   wlchip_serial_id_v01,
+					   serial_id_lsb),
+	},
+	{
+		.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,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   initiate_cal_download_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   initiate_cal_download_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   initiate_cal_update_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   initiate_cal_update_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   msa_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   msa_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   pin_connect_result_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   pin_connect_result_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   client_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   client_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   request_mem_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   request_mem_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_mem_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_mem_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_init_done_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_init_done_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   rejuvenate_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   rejuvenate_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   xo_cal_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   xo_cal_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   cal_done_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   cal_done_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_req_mem_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_req_mem_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_save_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_save_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_free_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_trace_free_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   respond_get_info_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   respond_get_info_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   m3_dump_upload_req_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   m3_dump_upload_req_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   wfc_call_twt_config_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   wfc_call_twt_config_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_mem_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   qdss_mem_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   m3_dump_upload_segments_req_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   m3_dump_upload_segments_req_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_ssr_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_ssr_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   async_data_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   async_data_enable),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_ind_register_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_ind_register_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_ind_register_resp_msg_v01,
+					   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_ind_register_resp_msg_v01,
+					   fw_status_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_resp_msg_v01,
+					   fw_status),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_ind_register_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_fw_ready_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_msa_ready_ind_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_msa_ready_ind_msg_v01,
+					   hang_data_addr_offset_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_msa_ready_ind_msg_v01,
+					   hang_data_addr_offset),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_msa_ready_ind_msg_v01,
+					   hang_data_length_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_msa_ready_ind_msg_v01,
+					   hang_data_length),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_msa_ready_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_pin_connect_result_ind_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_pin_connect_result_ind_msg_v01,
+					   pwr_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   pwr_pin_result),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   phy_io_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   phy_io_pin_result),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   rf_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   rf_pin_result),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_pin_connect_result_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_driver_mode_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   mode),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   hw_debug_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   hw_debug),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   xo_cal_data_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   xo_cal_data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   wlan_en_delay_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wlan_mode_req_msg_v01,
+					   wlan_en_delay),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wlan_mode_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wlan_mode_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_mode_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_mode_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wlan_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_cfg_req_msg_v01,
+					   host_version_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   host_version),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_CE_V01,
+		.elem_size      = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg),
+		.ei_array      = wlfw_ce_tgt_pipe_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SVC_V01,
+		.elem_size      = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg),
+		.ei_array      = wlfw_ce_svc_pipe_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHADOW_REG_V01,
+		.elem_size      = sizeof(struct wlfw_shadow_reg_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg),
+		.ei_array      = wlfw_shadow_reg_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01,
+		.elem_size      = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2),
+		.ei_array      = wlfw_shadow_reg_v2_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   rri_over_ddr_cfg_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_rri_over_ddr_cfg_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   rri_over_ddr_cfg),
+		.ei_array      = wlfw_rri_over_ddr_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   msi_cfg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   msi_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_CE_V01,
+		.elem_size      = sizeof(struct wlfw_msi_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   msi_cfg),
+		.ei_array      = wlfw_msi_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v3_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v3_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHADOW_REG_V3_V01,
+		.elem_size      = sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v3),
+		.ei_array      = wlfw_shadow_reg_v3_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wlan_cfg_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wlan_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_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_cfg_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cap_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cap_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cap_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_cap_resp_msg_v01,
+					   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_cap_resp_msg_v01,
+					   chip_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_rf_chip_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   chip_info),
+		.ei_array      = wlfw_rf_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   board_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_rf_board_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   board_info),
+		.ei_array      = wlfw_rf_board_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   soc_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_soc_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   soc_info),
+		.ei_array      = wlfw_soc_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_version_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_fw_version_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_version_info),
+		.ei_array      = wlfw_fw_version_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_build_id_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_build_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   num_macs_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   num_macs),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   voltage_mv_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   voltage_mv),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   time_freq_hz_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   time_freq_hz),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   otp_version_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   otp_version),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   eeprom_caldata_read_timeout_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   eeprom_caldata_read_timeout),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_caps_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   fw_caps),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   rd_card_chain_cap_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_rd_card_chain_cap_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   rd_card_chain_cap),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   dev_mem_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_DEV_MEM_NUM_V01,
+		.elem_size      = sizeof(struct wlfw_dev_mem_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   dev_mem_info),
+		.ei_array      = wlfw_dev_mem_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   foundry_name_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   foundry_name),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hang_data_addr_offset_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hang_data_addr_offset),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hang_data_length_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hang_data_length),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   bdf_dnld_method_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_bdf_dnld_method_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   bdf_dnld_method),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hwid_bitmap_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   hwid_bitmap),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   ol_cpr_cfg_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_pmu_cfg_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   ol_cpr_cfg),
+		.ei_array      = wlfw_pmu_cfg_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   regdb_mandatory_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   regdb_mandatory),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   regdb_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   regdb_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   rxgainlut_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   rxgainlut_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x26,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   he_channel_width_cap_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_he_channel_width_cap_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x26,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   he_channel_width_cap),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x27,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   phy_qam_cap_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_phy_qam_cap_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x27,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   phy_qam_cap),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x28,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   serial_id_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlchip_serial_id_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x28,
+		.offset         = offsetof(struct
+					   wlfw_cap_resp_msg_v01,
+					   serial_id),
+		.ei_array      = wlchip_serial_id_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cap_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   valid),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   bdf_type_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_req_msg_v01,
+					   bdf_type),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_bdf_download_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_bdf_download_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_bdf_download_resp_msg_v01,
+					   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_bdf_download_resp_msg_v01,
+					   host_bdf_data_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_resp_msg_v01,
+					   host_bdf_data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_bdf_download_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   meta_data_len),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = QMI_WLFW_MAX_NUM_CAL_V01,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   meta_data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   xo_cal_data_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   xo_cal_data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_remove_supported_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_remove_supported),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_file_download_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_report_req_msg_v01,
+					   cal_file_download_size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cal_report_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_report_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_cal_report_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_cal_report_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_download_ind_msg_v01,
+					   cal_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_download_ind_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_download_ind_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_download_ind_msg_v01,
+					   cal_data_location_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_download_ind_msg_v01,
+					   cal_data_location),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_initiate_cal_download_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   valid),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   cal_data_location_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_req_msg_v01,
+					   cal_data_location),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cal_download_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_download_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_cal_download_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_cal_download_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   cal_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   cal_data_location_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   cal_data_location),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_initiate_cal_update_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_req_msg_v01,
+					   cal_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cal_update_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_update_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_cal_update_resp_msg_v01,
+					   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_cal_update_resp_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   cal_data_location_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_cal_update_resp_msg_v01,
+					   cal_data_location),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cal_update_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_msa_info_req_msg_v01,
+					   msa_addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_msa_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_msa_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_msa_info_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_msa_info_resp_msg_v01,
+					   resp),
+		.ei_array      = qmi_response_type_v01_ei,
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_msa_info_resp_msg_v01,
+					   mem_region_info_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01,
+		.elem_size      = sizeof(struct wlfw_memory_region_info_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_msa_info_resp_msg_v01,
+					   mem_region_info),
+		.ei_array      = wlfw_memory_region_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_msa_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_msa_ready_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_msa_ready_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_msa_ready_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_msa_ready_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_ini_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_ini_req_msg_v01,
+					   enablefwlog_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ini_req_msg_v01,
+					   enablefwlog),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_ini_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_ini_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_ini_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_ini_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_req_msg_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_req_msg_v01,
+					   mem_type),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_athdiag_read_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_athdiag_read_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_athdiag_read_resp_msg_v01,
+					   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_athdiag_read_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_athdiag_read_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   mem_type),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_athdiag_write_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_athdiag_write_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_athdiag_write_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_athdiag_write_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_vbatt_req_msg_v01,
+					   voltage_uv),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_vbatt_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_vbatt_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_vbatt_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_vbatt_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_mac_addr_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_mac_addr_req_msg_v01,
+					   mac_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAC_ADDR_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_mac_addr_req_msg_v01,
+					   mac_addr),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_mac_addr_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_mac_addr_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_mac_addr_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_mac_addr_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_host_cap_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_host_cap_req_msg_v01,
+					   num_clients_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   num_clients),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wake_msi_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wake_msi),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpios_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpios_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = QMI_WLFW_MAX_NUM_GPIO_V01,
+		.elem_size      = sizeof(u32),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpios),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   nm_modem_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   nm_modem),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   bdf_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   bdf_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   bdf_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   bdf_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   m3_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   m3_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   m3_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   m3_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_filesys_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_filesys_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_cache_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_cache_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_done_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1A,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_done),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mem_bucket_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1B,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mem_bucket),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mem_cfg_mode_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1C,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mem_cfg_mode),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_duration_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1D,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   cal_duration),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   platform_name_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_PLATFORM_NAME_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1E,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   platform_name),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   ddr_range_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_HOST_DDR_RANGE_SIZE_V01,
+		.elem_size      = sizeof(struct wlfw_host_ddr_range_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x1F,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   ddr_range),
+		.ei_array      = wlfw_host_ddr_range_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   host_build_type_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_host_build_type_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x20,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   host_build_type),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_capable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x21,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_capable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x22,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_group_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x23,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_group_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   max_mlo_peer_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x24,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   max_mlo_peer),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_num_chips_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x25,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_num_chips),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x26,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_MLO_CHIP_V01,
+		.elem_size      = sizeof(struct mlo_chip_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x26,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_info),
+		.ei_array      = mlo_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x27,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   feature_list_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x27,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   feature_list),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x28,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   num_wlan_clients_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x28,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   num_wlan_clients),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x29,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   num_wlan_vaps_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x29,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   num_wlan_vaps),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2A,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wake_msi_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2A,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wake_msi_addr),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2B,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wlan_enable_delay_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2B,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   wlan_enable_delay),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2C,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   ddr_type_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2C,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   ddr_type),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2D,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpio_info_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2D,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpio_info_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = QMI_WLFW_MAX_NUM_GPIO_INFO_V01,
+		.elem_size      = sizeof(u32),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x2D,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   gpio_info),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2E,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   fw_ini_cfg_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2E,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   fw_ini_cfg_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x2F,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_v2_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MLO_V2_CHP_V01,
+		.elem_size      = sizeof(struct mlo_chip_v2_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x2F,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   mlo_chip_v2_info),
+		.ei_array      = mlo_chip_v2_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x30,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   pcie_link_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_host_pcie_link_info_s_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x30,
+		.offset         = offsetof(struct
+					   wlfw_host_cap_req_msg_v01,
+					   pcie_link_info),
+		.ei_array      = wlfw_host_pcie_link_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_host_cap_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_host_cap_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_host_cap_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_host_cap_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_request_mem_ind_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_request_mem_ind_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_request_mem_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_respond_mem_req_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_resp_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_respond_mem_req_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_resp_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_respond_mem_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_respond_mem_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_respond_mem_resp_msg_v01,
+					   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,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_respond_mem_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_fw_mem_ready_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_fw_init_done_ind_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_fw_init_done_ind_msg_v01,
+					   hang_data_addr_offset_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
+					   hang_data_addr_offset),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
+					   hang_data_length_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
+					   hang_data_length),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
+					   soft_sku_features_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_fw_init_done_ind_msg_v01,
+					   soft_sku_features),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_fw_init_done_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_rejuvenate_ind_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_rejuvenate_ind_msg_v01,
+					   cause_for_rejuvenation_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   cause_for_rejuvenation),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   requesting_sub_system_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   requesting_sub_system),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   line_number_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   line_number),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   function_name_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ind_msg_v01,
+					   function_name),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_rejuvenate_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_rejuvenate_ack_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_rejuvenate_ack_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_rejuvenate_ack_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_rejuvenate_ack_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_dynamic_feature_mask_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_dynamic_feature_mask_req_msg_v01,
+					   mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_dynamic_feature_mask_req_msg_v01,
+					   mask),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_dynamic_feature_mask_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_dynamic_feature_mask_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_dynamic_feature_mask_resp_msg_v01,
+					   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_dynamic_feature_mask_resp_msg_v01,
+					   prev_mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_dynamic_feature_mask_resp_msg_v01,
+					   prev_mask),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_dynamic_feature_mask_resp_msg_v01,
+					   curr_mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_dynamic_feature_mask_resp_msg_v01,
+					   curr_mask),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_dynamic_feature_mask_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_m3_info_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_m3_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_m3_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_info_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_m3_info_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_m3_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_xo_cal_ind_msg_v01,
+					   xo_cal_data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_xo_cal_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_cal_done_ind_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_cal_done_ind_msg_v01,
+					   cal_file_upload_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_cal_done_ind_msg_v01,
+					   cal_file_upload_size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_cal_done_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_req_mem_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_req_mem_ind_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_req_mem_ind_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_req_mem_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_mem_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mem_info_req_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_resp_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mem_info_req_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_resp_s_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_qdss_trace_mem_info_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mem_info_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_mem_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_mem_info_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_qdss_trace_mem_info_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_qdss_trace_mem_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_save_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   source),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   mem_seg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_resp_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_resp_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   file_name_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_save_ind_msg_v01,
+					   file_name),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_save_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_data_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_data_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_data_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_qdss_trace_data_resp_msg_v01,
+					   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_qdss_trace_data_resp_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_data_resp_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_data_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_config_download_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_qdss_trace_config_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_config_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_config_download_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_config_download_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_qdss_trace_config_download_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_qdss_trace_config_download_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_mode_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_qdss_trace_mode_req_msg_v01,
+					   mode_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_qdss_trace_mode_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mode_req_msg_v01,
+					   mode),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mode_req_msg_v01,
+					   option_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mode_req_msg_v01,
+					   option),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mode_req_msg_v01,
+					   hw_trc_disable_override_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_qmi_param_value_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_mode_req_msg_v01,
+					   hw_trc_disable_override),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_mode_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_mode_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_qdss_trace_mode_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_qdss_trace_mode_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_trace_free_ind_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_qdss_trace_free_ind_msg_v01,
+					   mem_seg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_free_ind_msg_v01,
+					   mem_seg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+		.elem_size      = sizeof(struct wlfw_mem_seg_resp_s_v01),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_qdss_trace_free_ind_msg_v01,
+					   mem_seg),
+		.ei_array      = wlfw_mem_seg_resp_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_trace_free_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_shutdown_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_shutdown_req_msg_v01,
+					   shutdown_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_shutdown_req_msg_v01,
+					   shutdown),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_shutdown_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_shutdown_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_shutdown_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_shutdown_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_antenna_switch_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_antenna_switch_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_antenna_switch_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_antenna_switch_resp_msg_v01,
+					   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_antenna_switch_resp_msg_v01,
+					   antenna_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_antenna_switch_resp_msg_v01,
+					   antenna),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_antenna_switch_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_antenna_grant_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_antenna_grant_req_msg_v01,
+					   grant_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_antenna_grant_req_msg_v01,
+					   grant),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_antenna_grant_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_antenna_grant_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_antenna_grant_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_antenna_grant_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wfc_call_status_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   wfc_call_status_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_WFC_CALL_STATUS_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   wfc_call_status),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   wfc_call_active_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   wfc_call_active),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   all_wfc_calls_held_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   all_wfc_calls_held),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   is_wfc_emergency_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   is_wfc_emergency),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   twt_ims_start_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   twt_ims_start),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   twt_ims_int_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   twt_ims_int),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   media_quality_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_wfc_media_quality_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_status_req_msg_v01,
+					   media_quality),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wfc_call_status_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wfc_call_status_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_wfc_call_status_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_wfc_call_status_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_get_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_get_info_req_msg_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_get_info_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_get_info_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_get_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_get_info_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_get_info_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_get_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_respond_get_info_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   type_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   is_last_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   is_last),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   seq_no_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_respond_get_info_ind_msg_v01,
+					   seq_no),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_respond_get_info_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_device_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_device_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_device_info_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_device_info_resp_msg_v01,
+					   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_device_info_resp_msg_v01,
+					   bar_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   bar_addr),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   bar_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   bar_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_addr),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_device_info_resp_msg_v01,
+					   mhi_state_info_size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_device_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_dump_upload_req_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_req_ind_msg_v01,
+					   pdev_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_req_ind_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_req_ind_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_m3_dump_upload_req_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_dump_upload_done_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_done_req_msg_v01,
+					   pdev_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_done_req_msg_v01,
+					   status),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_m3_dump_upload_done_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_dump_upload_done_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_m3_dump_upload_done_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_m3_dump_upload_done_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_soc_wake_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_soc_wake_req_msg_v01,
+					   wake_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_soc_wake_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_soc_wake_req_msg_v01,
+					   wake),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_soc_wake_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_soc_wake_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_soc_wake_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_soc_wake_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_power_save_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_power_save_req_msg_v01,
+					   power_save_mode_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_power_save_mode_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_power_save_req_msg_v01,
+					   power_save_mode),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_power_save_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_power_save_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_power_save_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_power_save_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_wfc_call_twt_config_ind_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_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_start_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_start),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_int_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_int),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_upo_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_upo),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_sp_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_sp),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_dl_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_dl),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_config_changed_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_wfc_call_twt_config_ind_msg_v01,
+					   twt_sta_config_changed),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_wfc_call_twt_config_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_qdss_mem_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_qdss_mem_ready_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_pcie_gen_switch_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pcie_gen_speed_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_pcie_gen_switch_req_msg_v01,
+					   pcie_speed),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_pcie_gen_switch_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_pcie_gen_switch_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_pcie_gen_switch_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_pcie_gen_switch_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+					   pdev_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+					   no_of_valid_segments),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01,
+		.elem_size      = sizeof(struct wlfw_m3_segment_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_m3_dump_upload_segments_req_ind_msg_v01,
+					   m3_segment),
+		.ei_array      = wlfw_m3_segment_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_subsys_restart_level_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_subsys_restart_level_req_msg_v01,
+					   restart_level_type_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_subsys_restart_level_req_msg_v01,
+					   restart_level_type),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_subsys_restart_level_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_subsys_restart_level_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_subsys_restart_level_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_subsys_restart_level_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_ini_file_download_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_ini_file_download_req_msg_v01,
+					   file_type_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_ini_file_type_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   file_type),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_ini_file_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_ini_file_download_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_ini_file_download_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_ini_file_download_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_ini_file_download_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_phy_cap_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_phy_cap_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_phy_cap_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_phy_cap_resp_msg_v01,
+					   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_phy_cap_resp_msg_v01,
+					   num_phy_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   num_phy),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   board_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   board_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   mlo_cap_v2_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   mlo_cap_v2_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   single_chip_mlo_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_phy_cap_resp_msg_v01,
+					   single_chip_mlo_support),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+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);
+
+struct qmi_elem_info wlfw_pcie_link_ctrl_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pcie_link_state_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_pcie_link_ctrl_req_msg_v01,
+					   link_state_req),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_pcie_link_ctrl_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_pcie_link_ctrl_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_pcie_link_ctrl_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_pcie_link_ctrl_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_aux_uc_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_aux_uc_info_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_aux_uc_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_aux_uc_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_aux_uc_info_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_aux_uc_info_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_aux_uc_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_tme_lite_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_tme_lite_file_type_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_tme_lite_info_req_msg_v01,
+					   tme_file),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_tme_lite_info_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_tme_lite_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_tme_lite_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_tme_lite_info_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_tme_lite_info_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_tme_lite_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_soft_sku_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_soft_sku_info_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_soft_sku_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_soft_sku_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_soft_sku_info_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_soft_sku_info_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_soft_sku_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_fw_ssr_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_fw_ssr_reason_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_fw_ssr_ind_msg_v01,
+					   reason_code),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_fw_ssr_ind_msg_v01_ei);
+
+struct qmi_elem_info wlfw_bmps_ctrl_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_bmps_state_enum_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_bmps_ctrl_req_msg_v01,
+					   bmps_state),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_bmps_ctrl_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_bmps_ctrl_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_bmps_ctrl_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_bmps_ctrl_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_lpass_ssr_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_lpass_ssr_reason_v01),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_lpass_ssr_req_msg_v01,
+					   reason_code),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_lpass_ssr_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_lpass_ssr_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_lpass_ssr_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_lpass_ssr_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_mlo_reconfig_info_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_mlo_reconfig_info_req_msg_v01,
+					   mlo_capable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_capable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_group_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_group_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   max_mlo_peer_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   max_mlo_peer),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_num_chips_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_num_chips),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_MLO_CHIP_V01,
+		.elem_size      = sizeof(struct mlo_chip_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_info),
+		.ei_array      = mlo_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_v2_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MLO_V2_CHP_V01,
+		.elem_size      = sizeof(struct mlo_chip_v2_info_s_v01),
+		.array_type       = STATIC_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct
+					   wlfw_mlo_reconfig_info_req_msg_v01,
+					   mlo_chip_v2_info),
+		.ei_array      = mlo_chip_v2_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_mlo_reconfig_info_req_msg_v01_ei);
+
+struct qmi_elem_info wlfw_mlo_reconfig_info_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_mlo_reconfig_info_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_mlo_reconfig_info_resp_msg_v01_ei);
+
+struct qmi_elem_info wlfw_driver_async_data_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_driver_async_data_ind_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.array_type       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_driver_async_data_ind_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.array_type       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_driver_async_data_ind_msg_v01,
+					   type),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.array_type       = NO_ARRAY,
+		.tlv_type       = QMI_COMMON_TLV_TYPE,
+	},
+};
+EXPORT_SYMBOL(wlfw_driver_async_data_ind_msg_v01_ei);
+
+/**
+ * wlfw_is_valid_dt_node_found - Check if valid device tree node present
+ *
+ * Valid device tree node means a node with "qcom,wlan" property present and
+ * "status" property not disabled.
+ *
+ * Return: true if valid device tree node found, false if not found
+ */
+static bool wlfw_is_valid_dt_node_found(void)
+{
+	struct device_node *dn = NULL;
+
+	for_each_node_with_property(dn, "qcom,wlan") {
+		if (of_device_is_available(dn))
+			break;
+	}
+
+	if (dn)
+		return true;
+
+	return false;
+}
+
+static int __init wlfw_init(void)
+{
+	if (!wlfw_is_valid_dt_node_found())
+		return -ENODEV;
+
+	return 0;
+}
+
+module_init(wlfw_init);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("WLAN FW QMI service");

+ 1637 - 0
qcom/opensource/wlan/platform/cnss_utils/wlan_firmware_service_v01.h

@@ -0,0 +1,1637 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
+
+#ifndef WLAN_FIRMWARE_SERVICE_V01_H
+#define WLAN_FIRMWARE_SERVICE_V01_H
+
+#include <linux/soc/qcom/qmi.h>
+
+#define WLFW_SERVICE_ID_V01 0x45
+#define WLFW_SERVICE_VERS_V01 0x01
+
+#define QMI_WLFW_SUBSYS_RESTART_LEVEL_RESP_V01 0x0055
+#define QMI_WLFW_SUBSYS_RESTART_LEVEL_REQ_V01 0x0055
+#define QMI_WLFW_POWER_SAVE_RESP_V01 0x0050
+#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_INI_FILE_DOWNLOAD_RESP_V01 0x0056
+#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
+#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
+#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
+#define QMI_WLFW_PCIE_LINK_CTRL_RESP_V01 0x0059
+#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
+#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
+#define QMI_WLFW_QDSS_TRACE_MODE_RESP_V01 0x0045
+#define QMI_WLFW_AUX_UC_INFO_REQ_V01 0x005A
+#define QMI_WLFW_FW_READY_IND_V01 0x0021
+#define QMI_WLFW_SOFT_SKU_INFO_RESP_V01 0x0060
+#define QMI_WLFW_QDSS_TRACE_MEM_INFO_RESP_V01 0x0040
+#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
+#define QMI_WLFW_PHY_CAP_REQ_V01 0x0057
+#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
+#define QMI_WLFW_QDSS_TRACE_DATA_RESP_V01 0x0042
+#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
+#define QMI_WLFW_QDSS_TRACE_MODE_REQ_V01 0x0045
+#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
+#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
+#define QMI_WLFW_BMPS_CTRL_RESP_V01 0x005D
+#define QMI_WLFW_LPASS_SSR_RESP_V01 0x005E
+#define QMI_WLFW_AUX_UC_INFO_RESP_V01 0x005A
+#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
+#define QMI_WLFW_PCIE_GEN_SWITCH_REQ_V01 0x0053
+#define QMI_WLFW_ANTENNA_GRANT_RESP_V01 0x0048
+#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
+#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
+#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
+#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
+#define QMI_WLFW_SOC_WAKE_REQ_V01 0x004F
+#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
+#define QMI_WLFW_M3_DUMP_UPLOAD_DONE_RESP_V01 0x004E
+#define QMI_WLFW_QDSS_TRACE_SAVE_IND_V01 0x0041
+#define QMI_WLFW_DRIVER_ASYNC_DATA_IND_V01 0x0061
+#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
+#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
+#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
+#define QMI_WLFW_TME_LITE_INFO_RESP_V01 0x005B
+#define QMI_WLFW_SHUTDOWN_REQ_V01 0x0043
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_PCIE_LINK_CTRL_REQ_V01 0x0059
+#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
+#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
+#define QMI_WLFW_MLO_RECONFIG_INFO_REQ_V01 0x005F
+#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_LPASS_SSR_REQ_V01 0x005E
+#define QMI_WLFW_MLO_RECONFIG_INFO_RESP_V01 0x005F
+#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_INI_RESP_V01 0x002F
+#define QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01 0x0040
+#define QMI_WLFW_ANTENNA_SWITCH_REQ_V01 0x0047
+#define QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01 0x003F
+#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
+#define QMI_WLFW_FW_SSR_IND_V01 0x005C
+#define QMI_WLFW_PHY_CAP_RESP_V01 0x0057
+#define QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_RESP_V01 0x0044
+#define QMI_WLFW_SOC_WAKE_RESP_V01 0x004F
+#define QMI_WLFW_GET_INFO_RESP_V01 0x004A
+#define QMI_WLFW_BMPS_CTRL_REQ_V01 0x005D
+#define QMI_WLFW_PCIE_GEN_SWITCH_RESP_V01 0x0053
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define QMI_WLFW_M3_DUMP_UPLOAD_SEGMENTS_REQ_IND_V01 0x0054
+#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
+#define QMI_WLFW_M3_DUMP_UPLOAD_DONE_REQ_V01 0x004E
+#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_ANTENNA_SWITCH_RESP_V01 0x0047
+#define QMI_WLFW_DEVICE_INFO_REQ_V01 0x004C
+#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
+#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
+#define QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01 0x0044
+#define QMI_WLFW_GET_INFO_REQ_V01 0x004A
+#define QMI_WLFW_SOFT_SKU_INFO_REQ_V01 0x0060
+#define QMI_WLFW_CAL_DONE_IND_V01 0x003E
+#define QMI_WLFW_M3_DUMP_UPLOAD_REQ_IND_V01 0x004D
+#define QMI_WLFW_WFC_CALL_STATUS_RESP_V01 0x0049
+#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
+#define QMI_WLFW_POWER_SAVE_REQ_V01 0x0050
+#define QMI_WLFW_XO_CAL_IND_V01 0x003D
+#define QMI_WLFW_SHUTDOWN_RESP_V01 0x0043
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
+#define QMI_WLFW_WFC_CALL_TWT_CONFIG_IND_V01 0x0051
+#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
+#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_TME_LITE_INFO_REQ_V01 0x005B
+#define QMI_WLFW_QDSS_MEM_READY_IND_V01 0x0052
+
+#define QMI_WLFW_MAX_NUM_CAL_V01 5
+#define QMI_WLFW_MAX_PLATFORM_NAME_LEN_V01 64
+#define QMI_WLFW_MAX_HOST_DDR_RANGE_SIZE_V01 3
+#define QMI_WLFW_MAX_MLO_CHIP_V01 3
+#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
+#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
+#define QMI_WLFW_MAX_NUM_GPIO_INFO_V01 20
+#define QMI_WLFW_MLO_V2_CHP_V01 4
+#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2
+#define QMI_WLFW_PMU_PARAMS_MAX_V01 16
+#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 52
+#define QMI_WLFW_MAX_WFC_CALL_STATUS_DATA_SIZE_V01 256
+#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
+#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_CE_V01 12
+#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
+#define QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01 10
+#define QMI_WLFW_PMU_PIN_NAME_MAX_LEN_V01 32
+#define QMI_WLFW_MAX_STR_LEN_V01 16
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V3_V01 60
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01 36
+#define QMI_WLFW_MAX_ADJ_CHIP_V01 2
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 40
+#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_NUM_GPIO_V01 32
+
+enum wlfw_driver_mode_enum_v01 {
+	WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_MISSION_V01 = 0,
+	QMI_WLFW_FTM_V01 = 1,
+	QMI_WLFW_EPPING_V01 = 2,
+	QMI_WLFW_WALTEST_V01 = 3,
+	QMI_WLFW_OFF_V01 = 4,
+	QMI_WLFW_CCPM_V01 = 5,
+	QMI_WLFW_QVIT_V01 = 6,
+	QMI_WLFW_CALIBRATION_V01 = 7,
+	QMI_WLFW_FTM_CALIBRATION_V01 = 10,
+	WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_cal_temp_id_enum_v01 {
+	WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
+	QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
+	QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
+	QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
+	QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
+	WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_pipedir_enum_v01 {
+	WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+	QMI_WLFW_PIPEDIR_IN_V01 = 1,
+	QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+	QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+	WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_mem_type_enum_v01 {
+	WLFW_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_MEM_TYPE_MSA_V01 = 0,
+	QMI_WLFW_MEM_TYPE_DDR_V01 = 1,
+	QMI_WLFW_MEM_BDF_V01 = 2,
+	QMI_WLFW_MEM_M3_V01 = 3,
+	QMI_WLFW_MEM_CAL_V01 = 4,
+	QMI_WLFW_MEM_DPD_V01 = 5,
+	QMI_WLFW_MEM_QDSS_V01 = 6,
+	QMI_WLFW_MEM_HANG_DATA_V01 = 7,
+	QMI_WLFW_MLO_GLOBAL_MEM_V01 = 8,
+	QMI_WLFW_PAGEABLE_MEM_V01 = 9,
+	QMI_WLFW_AFC_MEM_V01 = 10,
+	QMI_WLFW_MEM_LPASS_SHARED_V01 = 11,
+	QMI_WLFW_MEM_CALDB_SEG_V01 = 12,
+	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,
+	QMI_WLFW_QDSS_TRACE_ON_V01 = 1,
+	WLFW_QDSS_TRACE_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_wfc_media_quality_v01 {
+	WLFW_WFC_MEDIA_QUALITY_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_WFC_MEDIA_QUAL_NOT_AVAILABLE_V01 = 0,
+	QMI_WLFW_WFC_MEDIA_QUAL_BAD_V01 = 1,
+	QMI_WLFW_WFC_MEDIA_QUAL_GOOD_V01 = 2,
+	QMI_WLFW_WFC_MEDIA_QUAL_EXCELLENT_V01 = 3,
+	WLFW_WFC_MEDIA_QUALITY_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_soc_wake_enum_v01 {
+	WLFW_SOC_WAKE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_WAKE_REQUEST_V01 = 0,
+	QMI_WLFW_WAKE_RELEASE_V01 = 1,
+	WLFW_SOC_WAKE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_host_build_type_v01 {
+	WLFW_HOST_BUILD_TYPE_MIN_VAL_V01 = INT_MIN,
+	QMI_HOST_BUILD_TYPE_UNSPECIFIED_V01 = 0,
+	QMI_HOST_BUILD_TYPE_PRIMARY_V01 = 1,
+	QMI_HOST_BUILD_TYPE_SECONDARY_V01 = 2,
+	WLFW_HOST_BUILD_TYPE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_qmi_param_value_v01 {
+	WLFW_QMI_PARAM_VALUE_MIN_VAL_V01 = INT_MIN,
+	QMI_PARAM_INVALID_V01 = 0,
+	QMI_PARAM_ENABLE_V01 = 1,
+	QMI_PARAM_DISABLE_V01 = 2,
+	WLFW_QMI_PARAM_VALUE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_rd_card_chain_cap_v01 {
+	WLFW_RD_CARD_CHAIN_CAP_MIN_VAL_V01 = INT_MIN,
+	WLFW_RD_CARD_CHAIN_CAP_UNSPECIFIED_V01 = 0,
+	WLFW_RD_CARD_CHAIN_CAP_1x1_V01 = 1,
+	WLFW_RD_CARD_CHAIN_CAP_2x2_V01 = 2,
+	WLFW_RD_CARD_CHAIN_CAP_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_he_channel_width_cap_v01 {
+	WLFW_HE_CHANNEL_WIDTH_CAP_MIN_VAL_V01 = INT_MIN,
+	WLFW_PHY_HE_CHANNEL_WIDTH_CAP_UNSPECIFIED_V01 = 0,
+	WLFW_PHY_HE_CHANNEL_WIDTH_CAP_80MHZ_V01 = 1,
+	WLFW_PHY_HE_CHANNEL_WIDTH_CAP_160MHZ_V01 = 2,
+	WLFW_HE_CHANNEL_WIDTH_CAP_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_phy_qam_cap_v01 {
+	WLFW_PHY_QAM_CAP_MIN_VAL_V01 = INT_MIN,
+	WLFW_PHY_QAM_CAP_UNSPECIFIED_V01 = 0,
+	WLFW_PHY_QAM_CAP_1K_V01 = 1,
+	WLFW_PHY_QAM_CAP_4K_V01 = 2,
+	WLFW_PHY_QAM_CAP_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_pcie_gen_speed_v01 {
+	WLFW_PCIE_GEN_SPEED_MIN_VAL_V01 = INT_MIN,
+	QMI_PCIE_GEN_SPEED_INVALID_V01 = 0,
+	QMI_PCIE_GEN_SPEED_1_V01 = 1,
+	QMI_PCIE_GEN_SPEED_2_V01 = 2,
+	QMI_PCIE_GEN_SPEED_3_V01 = 3,
+	WLFW_PCIE_GEN_SPEED_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_power_save_mode_v01 {
+	WLFW_POWER_SAVE_MODE_MIN_VAL_V01 = INT_MIN,
+	WLFW_POWER_SAVE_ENTER_V01 = 0,
+	WLFW_POWER_SAVE_EXIT_V01 = 1,
+	WLFW_POWER_SAVE_MODE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_m3_segment_type_v01 {
+	WLFW_M3_SEGMENT_TYPE_MIN_VAL_V01 = INT_MIN,
+	QMI_M3_SEGMENT_INVALID_V01 = 0,
+	QMI_M3_SEGMENT_PHYAREG_V01 = 1,
+	QMI_M3_SEGMENT_PHYDBG_V01 = 2,
+	QMI_M3_SEGMENT_WMAC0_REG_V01 = 3,
+	QMI_M3_SEGMENT_WCSSDBG_V01 = 4,
+	QMI_M3_SEGMENT_PHYAPDMEM_V01 = 5,
+	QMI_M3_SEGMENT_MAX_V01 = 6,
+	WLFW_M3_SEGMENT_TYPE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum cnss_feature_v01 {
+	CNSS_FEATURE_MIN_VAL_V01 = INT_MIN,
+	BOOTSTRAP_CLOCK_SELECT_V01 = 0,
+	CNSS_DRV_SUPPORT_V01 = 1,
+	CNSS_WLAN_EN_SUPPORT_V01 = 2,
+	CNSS_QDSS_CFG_MISS_V01 = 3,
+	CNSS_PCIE_PERST_NO_PULL_V01 = 4,
+	CNSS_RC_EP_ULTRASHORT_CHANNEL_V01 = 5,
+	CNSS_AUX_UC_SUPPORT_V01 = 6,
+	CNSS_MAX_FEATURE_V01 = 64,
+	CNSS_FEATURE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_bdf_dnld_method_v01 {
+	WLFW_BDF_DNLD_METHOD_MIN_VAL_V01 = INT_MIN,
+	WLFW_DIRECT_BDF_COPY_V01 = 0,
+	WLFW_SEND_BDF_OVER_QMI_V01 = 1,
+	WLFW_BDF_DNLD_METHOD_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_gpio_info_type_v01 {
+	WLFW_GPIO_INFO_TYPE_MIN_VAL_V01 = INT_MIN,
+	WLAN_EN_GPIO_V01 = 0,
+	BT_EN_GPIO_V01 = 1,
+	HOST_SOL_GPIO_V01 = 2,
+	TARGET_SOL_GPIO_V01 = 3,
+	WLAN_SW_CTRL_GPIO_V01 = 4,
+	GPIO_TYPE_MAX_V01 = 5,
+	WLFW_GPIO_INFO_TYPE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_ini_file_type_v01 {
+	WLFW_INI_FILE_TYPE_MIN_VAL_V01 = INT_MIN,
+	WLFW_INI_CFG_FILE_V01 = 0,
+	WLFW_CONN_ROAM_INI_V01 = 1,
+	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,
+};
+
+enum wlfw_pcie_link_state_enum_v01 {
+	WLFW_PCIE_LINK_STATE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_PCIE_ALLOW_LOW_PWR_V01 = 0,
+	QMI_WLFW_PCIE_PREVENT_LOW_PWR_V01 = 1,
+	WLFW_PCIE_LINK_STATE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_tme_lite_file_type_v01 {
+	WLFW_TME_LITE_FILE_TYPE_MIN_VAL_V01 = INT_MIN,
+	WLFW_TME_LITE_PATCH_FILE_V01 = 0,
+	WLFW_TME_LITE_OEM_FUSE_FILE_V01 = 1,
+	WLFW_TME_LITE_RPR_FILE_V01 = 2,
+	WLFW_TME_LITE_DPR_FILE_V01 = 3,
+	WLFW_TME_LITE_FILE_TYPE_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_bmps_state_enum_v01 {
+	WLFW_BMPS_STATE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_BMPS_ENABLE_V01 = 0,
+	QMI_WLFW_BMPS_DISABLE_V01 = 1,
+	WLFW_BMPS_STATE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_fw_ssr_reason_v01 {
+	WLFW_FW_SSR_REASON_MIN_VAL_V01 = INT_MIN,
+	WLFW_FW_SSR_REASON_DEFAULT_V01 = 0,
+	WLFW_FW_SSR_REASON_XPAN_V01 = 1,
+	WLFW_FW_SSR_REASON_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_lpass_ssr_reason_v01 {
+	WLFW_LPASS_SSR_REASON_MIN_VAL_V01 = INT_MIN,
+	WLFW_LPASS_SSR_REASON_NON_CE_V01 = 0,
+	WLFW_LPASS_SSR_REASON_CE_V01 = 1,
+	WLFW_LPASS_SSR_REASON_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)
+#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04)
+#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08)
+#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10)
+
+#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL)
+#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
+#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
+#define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL)
+#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL)
+
+#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
+
+#define QMI_WLFW_HW_XPA_V01 ((u64)0x01ULL)
+#define QMI_WLFW_CBC_FILE_DOWNLOAD_V01 ((u64)0x02ULL)
+
+#define QMI_WLFW_HOST_PCIE_GEN_SWITCH_V01 ((u64)0x01ULL)
+#define QMI_WLFW_DIRECT_LINK_SUPPORT_V01 ((u64)0x02ULL)
+#define QMI_WLFW_AUX_UC_SUPPORT_V01 ((u64)0x04ULL)
+#define QMI_WLFW_CALDB_SEG_DDR_SUPPORT_V01 ((u64)0x08ULL)
+
+#define QMI_WLFW_DIRECT_LINK_SKU_SUPPORT_V01 ((u64)0x01ULL)
+
+struct wlfw_ce_tgt_pipe_cfg_s_v01 {
+	u32 pipe_num;
+	enum wlfw_pipedir_enum_v01 pipe_dir;
+	u32 nentries;
+	u32 nbytes_max;
+	u32 flags;
+};
+
+struct wlfw_ce_svc_pipe_cfg_s_v01 {
+	u32 service_id;
+	enum wlfw_pipedir_enum_v01 pipe_dir;
+	u32 pipe_num;
+};
+
+struct wlfw_shadow_reg_cfg_s_v01 {
+	u16 id;
+	u16 offset;
+};
+
+struct wlfw_shadow_reg_v2_cfg_s_v01 {
+	u32 addr;
+};
+
+struct wlfw_rri_over_ddr_cfg_s_v01 {
+	u32 base_addr_low;
+	u32 base_addr_high;
+};
+
+struct wlfw_msi_cfg_s_v01 {
+	u16 ce_id;
+	u16 msi_vector;
+};
+
+struct wlfw_memory_region_info_s_v01 {
+	u64 region_addr;
+	u32 size;
+	u8 secure_flag;
+};
+
+struct wlfw_mem_cfg_s_v01 {
+	u64 offset;
+	u32 size;
+	u8 secure_flag;
+};
+
+struct wlfw_mem_seg_s_v01 {
+	u32 size;
+	enum wlfw_mem_type_enum_v01 type;
+	u32 mem_cfg_len;
+	struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01];
+};
+
+struct wlfw_mem_seg_resp_s_v01 {
+	u64 addr;
+	u32 size;
+	enum wlfw_mem_type_enum_v01 type;
+	u8 restore;
+};
+
+struct wlfw_rf_chip_info_s_v01 {
+	u32 chip_id;
+	u32 chip_family;
+};
+
+struct wlfw_rf_board_info_s_v01 {
+	u32 board_id;
+};
+
+struct wlfw_soc_info_s_v01 {
+	u32 soc_id;
+};
+
+struct wlfw_fw_version_info_s_v01 {
+	u32 fw_version;
+	char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+struct wlfw_host_ddr_range_s_v01 {
+	u64 start;
+	u64 size;
+};
+
+struct wlfw_m3_segment_info_s_v01 {
+	enum wlfw_m3_segment_type_v01 type;
+	u64 addr;
+	u64 size;
+	char name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+};
+
+struct wlfw_dev_mem_info_s_v01 {
+	u64 start;
+	u64 size;
+};
+
+struct mlo_chip_info_s_v01 {
+	u8 chip_id;
+	u8 num_local_links;
+	u8 hw_link_id[QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01];
+	u8 valid_mlo_link_id[QMI_WLFW_MAX_NUM_MLO_LINKS_PER_CHIP_V01];
+};
+
+struct mlo_chip_v2_info_s_v01 {
+	struct mlo_chip_info_s_v01 mlo_chip_info;
+	u8 adj_mlo_num_chips;
+	struct mlo_chip_info_s_v01 adj_mlo_chip_info[QMI_WLFW_MAX_ADJ_CHIP_V01];
+};
+
+struct wlfw_pmu_param_v01 {
+	u8 pin_name[QMI_WLFW_PMU_PIN_NAME_MAX_LEN_V01];
+	u32 wake_volt_valid;
+	u32 wake_volt;
+	u32 sleep_volt_valid;
+	u32 sleep_volt;
+};
+
+struct wlfw_pmu_cfg_v01 {
+	u32 pmu_param_len;
+	struct wlfw_pmu_param_v01 pmu_param[QMI_WLFW_PMU_PARAMS_MAX_V01];
+};
+
+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_host_pcie_link_info_s_v01 {
+	u32 pci_link_speed;
+	u32 pci_link_width;
+};
+
+struct wlchip_serial_id_v01 {
+	u32 serial_id_msb;
+	u32 serial_id_lsb;
+};
+
+struct wlfw_ind_register_req_msg_v01 {
+	u8 fw_ready_enable_valid;
+	u8 fw_ready_enable;
+	u8 initiate_cal_download_enable_valid;
+	u8 initiate_cal_download_enable;
+	u8 initiate_cal_update_enable_valid;
+	u8 initiate_cal_update_enable;
+	u8 msa_ready_enable_valid;
+	u8 msa_ready_enable;
+	u8 pin_connect_result_enable_valid;
+	u8 pin_connect_result_enable;
+	u8 client_id_valid;
+	u32 client_id;
+	u8 request_mem_enable_valid;
+	u8 request_mem_enable;
+	u8 fw_mem_ready_enable_valid;
+	u8 fw_mem_ready_enable;
+	u8 fw_init_done_enable_valid;
+	u8 fw_init_done_enable;
+	u8 rejuvenate_enable_valid;
+	u32 rejuvenate_enable;
+	u8 xo_cal_enable_valid;
+	u8 xo_cal_enable;
+	u8 cal_done_enable_valid;
+	u8 cal_done_enable;
+	u8 qdss_trace_req_mem_enable_valid;
+	u8 qdss_trace_req_mem_enable;
+	u8 qdss_trace_save_enable_valid;
+	u8 qdss_trace_save_enable;
+	u8 qdss_trace_free_enable_valid;
+	u8 qdss_trace_free_enable;
+	u8 respond_get_info_enable_valid;
+	u8 respond_get_info_enable;
+	u8 m3_dump_upload_req_enable_valid;
+	u8 m3_dump_upload_req_enable;
+	u8 wfc_call_twt_config_enable_valid;
+	u8 wfc_call_twt_config_enable;
+	u8 qdss_mem_ready_enable_valid;
+	u8 qdss_mem_ready_enable;
+	u8 m3_dump_upload_segments_req_enable_valid;
+	u8 m3_dump_upload_segments_req_enable;
+	u8 fw_ssr_enable_valid;
+	u8 fw_ssr_enable;
+	u8 async_data_enable_valid;
+	u8 async_data_enable;
+};
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 94
+extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[];
+
+struct wlfw_ind_register_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 fw_status_valid;
+	u64 fw_status;
+};
+#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[];
+
+struct wlfw_fw_ready_ind_msg_v01 {
+	char placeholder;
+};
+#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[];
+
+struct wlfw_msa_ready_ind_msg_v01 {
+	u8 hang_data_addr_offset_valid;
+	u32 hang_data_addr_offset;
+	u8 hang_data_length_valid;
+	u16 hang_data_length;
+};
+#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 12
+extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[];
+
+struct wlfw_pin_connect_result_ind_msg_v01 {
+	u8 pwr_pin_result_valid;
+	u32 pwr_pin_result;
+	u8 phy_io_pin_result_valid;
+	u32 phy_io_pin_result;
+	u8 rf_pin_result_valid;
+	u32 rf_pin_result;
+};
+#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
+
+struct wlfw_wlan_mode_req_msg_v01 {
+	enum wlfw_driver_mode_enum_v01 mode;
+	u8 hw_debug_valid;
+	u8 hw_debug;
+	u8 xo_cal_data_valid;
+	u8 xo_cal_data;
+	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[];
+
+struct wlfw_wlan_mode_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_req_msg_v01 {
+	u8 host_version_valid;
+	char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+	u8 tgt_cfg_valid;
+	u32 tgt_cfg_len;
+	struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+	u8 svc_cfg_valid;
+	u32 svc_cfg_len;
+	struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
+	u8 shadow_reg_valid;
+	u32 shadow_reg_len;
+	struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
+	u8 shadow_reg_v2_valid;
+	u32 shadow_reg_v2_len;
+	struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01];
+	u8 rri_over_ddr_cfg_valid;
+	struct wlfw_rri_over_ddr_cfg_s_v01 rri_over_ddr_cfg;
+	u8 msi_cfg_valid;
+	u32 msi_cfg_len;
+	struct wlfw_msi_cfg_s_v01 msi_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+	u8 shadow_reg_v3_valid;
+	u32 shadow_reg_v3_len;
+	struct wlfw_shadow_reg_v3_cfg_s_v01 shadow_reg_v3[QMI_WLFW_MAX_NUM_SHADOW_REG_V3_V01];
+};
+#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 1110
+extern struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
+
+struct wlfw_cap_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_cap_req_msg_v01_ei[];
+
+struct wlfw_cap_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 chip_info_valid;
+	struct wlfw_rf_chip_info_s_v01 chip_info;
+	u8 board_info_valid;
+	struct wlfw_rf_board_info_s_v01 board_info;
+	u8 soc_info_valid;
+	struct wlfw_soc_info_s_v01 soc_info;
+	u8 fw_version_info_valid;
+	struct wlfw_fw_version_info_s_v01 fw_version_info;
+	u8 fw_build_id_valid;
+	char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
+	u8 num_macs_valid;
+	u8 num_macs;
+	u8 voltage_mv_valid;
+	u32 voltage_mv;
+	u8 time_freq_hz_valid;
+	u32 time_freq_hz;
+	u8 otp_version_valid;
+	u32 otp_version;
+	u8 eeprom_caldata_read_timeout_valid;
+	u32 eeprom_caldata_read_timeout;
+	u8 fw_caps_valid;
+	u64 fw_caps;
+	u8 rd_card_chain_cap_valid;
+	enum wlfw_rd_card_chain_cap_v01 rd_card_chain_cap;
+	u8 dev_mem_info_valid;
+	struct wlfw_dev_mem_info_s_v01 dev_mem_info[QMI_WLFW_MAX_DEV_MEM_NUM_V01];
+	u8 foundry_name_valid;
+	char foundry_name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+	u8 hang_data_addr_offset_valid;
+	u32 hang_data_addr_offset;
+	u8 hang_data_length_valid;
+	u16 hang_data_length;
+	u8 bdf_dnld_method_valid;
+	enum wlfw_bdf_dnld_method_v01 bdf_dnld_method;
+	u8 hwid_bitmap_valid;
+	u8 hwid_bitmap;
+	u8 ol_cpr_cfg_valid;
+	struct wlfw_pmu_cfg_v01 ol_cpr_cfg;
+	u8 regdb_mandatory_valid;
+	u8 regdb_mandatory;
+	u8 regdb_support_valid;
+	u8 regdb_support;
+	u8 rxgainlut_support_valid;
+	u8 rxgainlut_support;
+	u8 he_channel_width_cap_valid;
+	enum wlfw_he_channel_width_cap_v01 he_channel_width_cap;
+	u8 phy_qam_cap_valid;
+	enum wlfw_phy_qam_cap_v01 phy_qam_cap;
+	u8 serial_id_valid;
+	struct wlchip_serial_id_v01 serial_id;
+};
+#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 1171
+extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[];
+
+struct wlfw_bdf_download_req_msg_v01 {
+	u8 valid;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+	u8 bdf_type_valid;
+	u8 bdf_type;
+};
+#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182
+extern struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[];
+
+struct wlfw_bdf_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 host_bdf_data_valid;
+	u64 host_bdf_data;
+};
+#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[];
+
+struct wlfw_cal_report_req_msg_v01 {
+	u32 meta_data_len;
+	enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+	u8 xo_cal_data_valid;
+	u8 xo_cal_data;
+	u8 cal_remove_supported_valid;
+	u8 cal_remove_supported;
+	u8 cal_file_download_size_valid;
+	u64 cal_file_download_size;
+};
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 43
+extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[];
+
+struct wlfw_cal_report_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_download_ind_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 cal_data_location_valid;
+	u32 cal_data_location;
+};
+#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
+
+struct wlfw_cal_download_req_msg_v01 {
+	u8 valid;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+	u8 cal_data_location_valid;
+	u32 cal_data_location;
+};
+#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6185
+extern struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[];
+
+struct wlfw_cal_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_update_ind_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+	u32 total_size;
+	u8 cal_data_location_valid;
+	u32 cal_data_location;
+};
+#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
+
+struct wlfw_cal_update_req_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+	u32 seg_id;
+};
+#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[];
+
+struct wlfw_cal_update_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+	u8 cal_data_location_valid;
+	u32 cal_data_location;
+};
+#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6188
+extern struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[];
+
+struct wlfw_msa_info_req_msg_v01 {
+	u64 msa_addr;
+	u32 size;
+};
+#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[];
+
+struct wlfw_msa_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u32 mem_region_info_len;
+	struct wlfw_memory_region_info_s_v01 mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+};
+#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
+extern struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[];
+
+struct wlfw_msa_ready_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[];
+
+struct wlfw_msa_ready_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[];
+
+struct wlfw_ini_req_msg_v01 {
+	u8 enablefwlog_valid;
+	u8 enablefwlog;
+};
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_ini_req_msg_v01_ei[];
+
+struct wlfw_ini_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_read_req_msg_v01 {
+	u32 offset;
+	u32 mem_type;
+	u32 data_len;
+};
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+	u32 offset;
+	u32 mem_type;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+	u64 voltage_uv;
+};
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
+struct wlfw_mac_addr_req_msg_v01 {
+	u8 mac_addr_valid;
+	u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
+extern struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[];
+
+struct wlfw_mac_addr_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[];
+
+struct wlfw_host_cap_req_msg_v01 {
+	u8 num_clients_valid;
+	u32 num_clients;
+	u8 wake_msi_valid;
+	u32 wake_msi;
+	u8 gpios_valid;
+	u32 gpios_len;
+	u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01];
+	u8 nm_modem_valid;
+	u8 nm_modem;
+	u8 bdf_support_valid;
+	u8 bdf_support;
+	u8 bdf_cache_support_valid;
+	u8 bdf_cache_support;
+	u8 m3_support_valid;
+	u8 m3_support;
+	u8 m3_cache_support_valid;
+	u8 m3_cache_support;
+	u8 cal_filesys_support_valid;
+	u8 cal_filesys_support;
+	u8 cal_cache_support_valid;
+	u8 cal_cache_support;
+	u8 cal_done_valid;
+	u8 cal_done;
+	u8 mem_bucket_valid;
+	u32 mem_bucket;
+	u8 mem_cfg_mode_valid;
+	u8 mem_cfg_mode;
+	u8 cal_duration_valid;
+	u16 cal_duration;
+	u8 platform_name_valid;
+	char platform_name[QMI_WLFW_MAX_PLATFORM_NAME_LEN_V01 + 1];
+	u8 ddr_range_valid;
+	struct wlfw_host_ddr_range_s_v01 ddr_range[QMI_WLFW_MAX_HOST_DDR_RANGE_SIZE_V01];
+	u8 host_build_type_valid;
+	enum wlfw_host_build_type_v01 host_build_type;
+	u8 mlo_capable_valid;
+	u8 mlo_capable;
+	u8 mlo_chip_id_valid;
+	u16 mlo_chip_id;
+	u8 mlo_group_id_valid;
+	u8 mlo_group_id;
+	u8 max_mlo_peer_valid;
+	u16 max_mlo_peer;
+	u8 mlo_num_chips_valid;
+	u8 mlo_num_chips;
+	u8 mlo_chip_info_valid;
+	struct mlo_chip_info_s_v01 mlo_chip_info[QMI_WLFW_MAX_MLO_CHIP_V01];
+	u8 feature_list_valid;
+	u64 feature_list;
+	u8 num_wlan_clients_valid;
+	u16 num_wlan_clients;
+	u8 num_wlan_vaps_valid;
+	u8 num_wlan_vaps;
+	u8 wake_msi_addr_valid;
+	u32 wake_msi_addr;
+	u8 wlan_enable_delay_valid;
+	u32 wlan_enable_delay;
+	u8 ddr_type_valid;
+	u32 ddr_type;
+	u8 gpio_info_valid;
+	u32 gpio_info_len;
+	u32 gpio_info[QMI_WLFW_MAX_NUM_GPIO_INFO_V01];
+	u8 fw_ini_cfg_support_valid;
+	u8 fw_ini_cfg_support;
+	u8 mlo_chip_v2_info_valid;
+	struct mlo_chip_v2_info_s_v01 mlo_chip_v2_info[QMI_WLFW_MLO_V2_CHP_V01];
+	u8 pcie_link_info_valid;
+	struct wlfw_host_pcie_link_info_s_v01 pcie_link_info;
+};
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 581
+extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
+
+struct wlfw_host_cap_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[];
+
+struct wlfw_request_mem_ind_msg_v01 {
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1824
+extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[];
+
+struct wlfw_respond_mem_req_msg_v01 {
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 888
+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 171
+extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[];
+
+struct wlfw_fw_mem_ready_ind_msg_v01 {
+	char placeholder;
+};
+#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_fw_init_done_ind_msg_v01 {
+	u8 hang_data_addr_offset_valid;
+	u32 hang_data_addr_offset;
+	u8 hang_data_length_valid;
+	u16 hang_data_length;
+	u8 soft_sku_features_valid;
+	u64 soft_sku_features;
+};
+#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 23
+extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ind_msg_v01 {
+	u8 cause_for_rejuvenation_valid;
+	u8 cause_for_rejuvenation;
+	u8 requesting_sub_system_valid;
+	u8 requesting_sub_system;
+	u8 line_number_valid;
+	u16 line_number;
+	u8 function_name_valid;
+	char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+};
+#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
+extern struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_req_msg_v01 {
+	u8 mask_valid;
+	u64 mask;
+};
+#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 prev_mask_valid;
+	u64 prev_mask;
+	u8 curr_mask_valid;
+	u64 curr_mask;
+};
+#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
+extern struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
+
+struct wlfw_m3_info_req_msg_v01 {
+	u64 addr;
+	u32 size;
+};
+#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[];
+
+struct wlfw_m3_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[];
+
+struct wlfw_xo_cal_ind_msg_v01 {
+	u8 xo_cal_data;
+};
+#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+
+struct wlfw_cal_done_ind_msg_v01 {
+	u8 cal_file_upload_size_valid;
+	u64 cal_file_upload_size;
+};
+#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_cal_done_ind_msg_v01_ei[];
+
+struct wlfw_qdss_trace_req_mem_ind_msg_v01 {
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+#define WLFW_QDSS_TRACE_REQ_MEM_IND_MSG_V01_MAX_MSG_LEN 1824
+extern struct qmi_elem_info wlfw_qdss_trace_req_mem_ind_msg_v01_ei[];
+
+struct wlfw_qdss_trace_mem_info_req_msg_v01 {
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_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[];
+
+struct wlfw_qdss_trace_mem_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_QDSS_TRACE_MEM_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_qdss_trace_mem_info_resp_msg_v01_ei[];
+
+struct wlfw_qdss_trace_save_ind_msg_v01 {
+	u32 source;
+	u32 total_size;
+	u8 mem_seg_valid;
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+	u8 file_name_valid;
+	char file_name[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+};
+#define WLFW_QDSS_TRACE_SAVE_IND_MSG_V01_MAX_MSG_LEN 921
+extern struct qmi_elem_info wlfw_qdss_trace_save_ind_msg_v01_ei[];
+
+struct wlfw_qdss_trace_data_req_msg_v01 {
+	u32 seg_id;
+};
+#define WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_qdss_trace_data_req_msg_v01_ei[];
+
+struct wlfw_qdss_trace_data_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+};
+#define WLFW_QDSS_TRACE_DATA_RESP_MSG_V01_MAX_MSG_LEN 6174
+extern struct qmi_elem_info wlfw_qdss_trace_data_resp_msg_v01_ei[];
+
+struct wlfw_qdss_trace_config_download_req_msg_v01 {
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+};
+#define WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6167
+extern struct qmi_elem_info wlfw_qdss_trace_config_download_req_msg_v01_ei[];
+
+struct wlfw_qdss_trace_config_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_qdss_trace_config_download_resp_msg_v01_ei[];
+
+struct wlfw_qdss_trace_mode_req_msg_v01 {
+	u8 mode_valid;
+	enum wlfw_qdss_trace_mode_enum_v01 mode;
+	u8 option_valid;
+	u64 option;
+	u8 hw_trc_disable_override_valid;
+	enum wlfw_qmi_param_value_v01 hw_trc_disable_override;
+};
+#define WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN 25
+extern struct qmi_elem_info wlfw_qdss_trace_mode_req_msg_v01_ei[];
+
+struct wlfw_qdss_trace_mode_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_QDSS_TRACE_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_qdss_trace_mode_resp_msg_v01_ei[];
+
+struct wlfw_qdss_trace_free_ind_msg_v01 {
+	u8 mem_seg_valid;
+	u32 mem_seg_len;
+	struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
+};
+#define WLFW_QDSS_TRACE_FREE_IND_MSG_V01_MAX_MSG_LEN 888
+extern struct qmi_elem_info wlfw_qdss_trace_free_ind_msg_v01_ei[];
+
+struct wlfw_shutdown_req_msg_v01 {
+	u8 shutdown_valid;
+	u8 shutdown;
+};
+#define WLFW_SHUTDOWN_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_shutdown_req_msg_v01_ei[];
+
+struct wlfw_shutdown_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_SHUTDOWN_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_shutdown_resp_msg_v01_ei[];
+
+struct wlfw_antenna_switch_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_ANTENNA_SWITCH_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_antenna_switch_req_msg_v01_ei[];
+
+struct wlfw_antenna_switch_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 antenna_valid;
+	u64 antenna;
+};
+#define WLFW_ANTENNA_SWITCH_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_antenna_switch_resp_msg_v01_ei[];
+
+struct wlfw_antenna_grant_req_msg_v01 {
+	u8 grant_valid;
+	u64 grant;
+};
+#define WLFW_ANTENNA_GRANT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct qmi_elem_info wlfw_antenna_grant_req_msg_v01_ei[];
+
+struct wlfw_antenna_grant_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_ANTENNA_GRANT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_antenna_grant_resp_msg_v01_ei[];
+
+struct wlfw_wfc_call_status_req_msg_v01 {
+	u32 wfc_call_status_len;
+	u8 wfc_call_status[QMI_WLFW_MAX_WFC_CALL_STATUS_DATA_SIZE_V01];
+	u8 wfc_call_active_valid;
+	u8 wfc_call_active;
+	u8 all_wfc_calls_held_valid;
+	u8 all_wfc_calls_held;
+	u8 is_wfc_emergency_valid;
+	u8 is_wfc_emergency;
+	u8 twt_ims_start_valid;
+	u64 twt_ims_start;
+	u8 twt_ims_int_valid;
+	u16 twt_ims_int;
+	u8 media_quality_valid;
+	enum wlfw_wfc_media_quality_v01 media_quality;
+};
+#define WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN 296
+extern struct qmi_elem_info wlfw_wfc_call_status_req_msg_v01_ei[];
+
+struct wlfw_wfc_call_status_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_WFC_CALL_STATUS_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_wfc_call_status_resp_msg_v01_ei[];
+
+struct wlfw_get_info_req_msg_v01 {
+	u8 type;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+};
+#define WLFW_GET_INFO_REQ_MSG_V01_MAX_MSG_LEN 6153
+extern struct qmi_elem_info wlfw_get_info_req_msg_v01_ei[];
+
+struct wlfw_get_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_GET_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_get_info_resp_msg_v01_ei[];
+
+struct wlfw_respond_get_info_ind_msg_v01 {
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 type_valid;
+	u8 type;
+	u8 is_last_valid;
+	u8 is_last;
+	u8 seq_no_valid;
+	u32 seq_no;
+};
+#define WLFW_RESPOND_GET_INFO_IND_MSG_V01_MAX_MSG_LEN 6164
+extern struct qmi_elem_info wlfw_respond_get_info_ind_msg_v01_ei[];
+
+struct wlfw_device_info_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_DEVICE_INFO_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_device_info_req_msg_v01_ei[];
+
+struct wlfw_device_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 bar_addr_valid;
+	u64 bar_addr;
+	u8 bar_size_valid;
+	u32 bar_size;
+	u8 mhi_state_info_addr_valid;
+	u64 mhi_state_info_addr;
+	u8 mhi_state_info_size_valid;
+	u32 mhi_state_info_size;
+};
+#define WLFW_DEVICE_INFO_RESP_MSG_V01_MAX_MSG_LEN 43
+extern struct qmi_elem_info wlfw_device_info_resp_msg_v01_ei[];
+
+struct wlfw_m3_dump_upload_req_ind_msg_v01 {
+	u32 pdev_id;
+	u64 addr;
+	u64 size;
+};
+#define WLFW_M3_DUMP_UPLOAD_REQ_IND_MSG_V01_MAX_MSG_LEN 29
+extern struct qmi_elem_info wlfw_m3_dump_upload_req_ind_msg_v01_ei[];
+
+struct wlfw_m3_dump_upload_done_req_msg_v01 {
+	u32 pdev_id;
+	u32 status;
+};
+#define WLFW_M3_DUMP_UPLOAD_DONE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct qmi_elem_info wlfw_m3_dump_upload_done_req_msg_v01_ei[];
+
+struct wlfw_m3_dump_upload_done_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_M3_DUMP_UPLOAD_DONE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_m3_dump_upload_done_resp_msg_v01_ei[];
+
+struct wlfw_soc_wake_req_msg_v01 {
+	u8 wake_valid;
+	enum wlfw_soc_wake_enum_v01 wake;
+};
+#define WLFW_SOC_WAKE_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_soc_wake_req_msg_v01_ei[];
+
+struct wlfw_soc_wake_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_SOC_WAKE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_soc_wake_resp_msg_v01_ei[];
+
+struct wlfw_power_save_req_msg_v01 {
+	u8 power_save_mode_valid;
+	enum wlfw_power_save_mode_v01 power_save_mode;
+};
+#define WLFW_POWER_SAVE_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_power_save_req_msg_v01_ei[];
+
+struct wlfw_power_save_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_POWER_SAVE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_power_save_resp_msg_v01_ei[];
+
+struct wlfw_wfc_call_twt_config_ind_msg_v01 {
+	u8 twt_sta_start_valid;
+	u64 twt_sta_start;
+	u8 twt_sta_int_valid;
+	u16 twt_sta_int;
+	u8 twt_sta_upo_valid;
+	u16 twt_sta_upo;
+	u8 twt_sta_sp_valid;
+	u16 twt_sta_sp;
+	u8 twt_sta_dl_valid;
+	u16 twt_sta_dl;
+	u8 twt_sta_config_changed_valid;
+	u8 twt_sta_config_changed;
+};
+#define WLFW_WFC_CALL_TWT_CONFIG_IND_MSG_V01_MAX_MSG_LEN 35
+extern struct qmi_elem_info wlfw_wfc_call_twt_config_ind_msg_v01_ei[];
+
+struct wlfw_qdss_mem_ready_ind_msg_v01 {
+	char placeholder;
+};
+#define WLFW_QDSS_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_qdss_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_pcie_gen_switch_req_msg_v01 {
+	enum wlfw_pcie_gen_speed_v01 pcie_speed;
+};
+#define WLFW_PCIE_GEN_SWITCH_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_pcie_gen_switch_req_msg_v01_ei[];
+
+struct wlfw_pcie_gen_switch_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_PCIE_GEN_SWITCH_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_pcie_gen_switch_resp_msg_v01_ei[];
+
+struct wlfw_m3_dump_upload_segments_req_ind_msg_v01 {
+	u32 pdev_id;
+	u32 no_of_valid_segments;
+	struct wlfw_m3_segment_info_s_v01 m3_segment[QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01];
+};
+#define WLFW_M3_DUMP_UPLOAD_SEGMENTS_REQ_IND_MSG_V01_MAX_MSG_LEN 387
+extern struct qmi_elem_info wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei[];
+
+struct wlfw_subsys_restart_level_req_msg_v01 {
+	u8 restart_level_type_valid;
+	u8 restart_level_type;
+};
+#define WLFW_SUBSYS_RESTART_LEVEL_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct qmi_elem_info wlfw_subsys_restart_level_req_msg_v01_ei[];
+
+struct wlfw_subsys_restart_level_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_SUBSYS_RESTART_LEVEL_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_subsys_restart_level_resp_msg_v01_ei[];
+
+struct wlfw_ini_file_download_req_msg_v01 {
+	u8 file_type_valid;
+	enum wlfw_ini_file_type_v01 file_type;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+};
+#define WLFW_INI_FILE_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6174
+extern struct qmi_elem_info wlfw_ini_file_download_req_msg_v01_ei[];
+
+struct wlfw_ini_file_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_INI_FILE_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_ini_file_download_resp_msg_v01_ei[];
+
+struct wlfw_phy_cap_req_msg_v01 {
+	char placeholder;
+};
+#define WLFW_PHY_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct qmi_elem_info wlfw_phy_cap_req_msg_v01_ei[];
+
+struct wlfw_phy_cap_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 num_phy_valid;
+	u8 num_phy;
+	u8 board_id_valid;
+	u32 board_id;
+	u8 mlo_cap_v2_support_valid;
+	u32 mlo_cap_v2_support;
+	u8 single_chip_mlo_support_valid;
+	u8 single_chip_mlo_support;
+};
+#define WLFW_PHY_CAP_RESP_MSG_V01_MAX_MSG_LEN 29
+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[];
+
+struct wlfw_pcie_link_ctrl_req_msg_v01 {
+	enum wlfw_pcie_link_state_enum_v01 link_state_req;
+};
+#define WLFW_PCIE_LINK_CTRL_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_pcie_link_ctrl_req_msg_v01_ei[];
+
+struct wlfw_pcie_link_ctrl_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_PCIE_LINK_CTRL_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_pcie_link_ctrl_resp_msg_v01_ei[];
+
+struct wlfw_aux_uc_info_req_msg_v01 {
+	u64 addr;
+	u32 size;
+};
+#define WLFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_aux_uc_info_req_msg_v01_ei[];
+
+struct wlfw_aux_uc_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_AUX_UC_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_aux_uc_info_resp_msg_v01_ei[];
+
+struct wlfw_tme_lite_info_req_msg_v01 {
+	enum wlfw_tme_lite_file_type_v01 tme_file;
+	u64 addr;
+	u32 size;
+};
+#define WLFW_TME_LITE_INFO_REQ_MSG_V01_MAX_MSG_LEN 25
+extern struct qmi_elem_info wlfw_tme_lite_info_req_msg_v01_ei[];
+
+struct wlfw_tme_lite_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_TME_LITE_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_tme_lite_info_resp_msg_v01_ei[];
+
+struct wlfw_soft_sku_info_req_msg_v01 {
+	u64 addr;
+	u32 size;
+};
+#define WLFW_SOFT_SKU_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct qmi_elem_info wlfw_soft_sku_info_req_msg_v01_ei[];
+
+struct wlfw_soft_sku_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_SOFT_SKU_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_soft_sku_info_resp_msg_v01_ei[];
+
+struct wlfw_fw_ssr_ind_msg_v01 {
+	enum wlfw_fw_ssr_reason_v01 reason_code;
+};
+#define WLFW_FW_SSR_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_fw_ssr_ind_msg_v01_ei[];
+
+struct wlfw_bmps_ctrl_req_msg_v01 {
+	enum wlfw_bmps_state_enum_v01 bmps_state;
+};
+#define WLFW_BMPS_CTRL_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_bmps_ctrl_req_msg_v01_ei[];
+
+struct wlfw_bmps_ctrl_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_BMPS_CTRL_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_bmps_ctrl_resp_msg_v01_ei[];
+
+struct wlfw_lpass_ssr_req_msg_v01 {
+	enum wlfw_lpass_ssr_reason_v01 reason_code;
+};
+#define WLFW_LPASS_SSR_REQ_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_lpass_ssr_req_msg_v01_ei[];
+
+struct wlfw_lpass_ssr_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_LPASS_SSR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_lpass_ssr_resp_msg_v01_ei[];
+
+struct wlfw_mlo_reconfig_info_req_msg_v01 {
+	u8 mlo_capable_valid;
+	u8 mlo_capable;
+	u8 mlo_chip_id_valid;
+	u16 mlo_chip_id;
+	u8 mlo_group_id_valid;
+	u8 mlo_group_id;
+	u8 max_mlo_peer_valid;
+	u16 max_mlo_peer;
+	u8 mlo_num_chips_valid;
+	u8 mlo_num_chips;
+	u8 mlo_chip_info_valid;
+	struct mlo_chip_info_s_v01 mlo_chip_info[QMI_WLFW_MAX_MLO_CHIP_V01];
+	u8 mlo_chip_v2_info_valid;
+	struct mlo_chip_v2_info_s_v01 mlo_chip_v2_info[QMI_WLFW_MLO_V2_CHP_V01];
+};
+#define WLFW_MLO_RECONFIG_INFO_REQ_MSG_V01_MAX_MSG_LEN 122
+extern struct qmi_elem_info wlfw_mlo_reconfig_info_req_msg_v01_ei[];
+
+struct wlfw_mlo_reconfig_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+#define WLFW_MLO_RECONFIG_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct qmi_elem_info wlfw_mlo_reconfig_info_resp_msg_v01_ei[];
+
+struct wlfw_driver_async_data_ind_msg_v01 {
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u16 type;
+};
+#define WLFW_DRIVER_ASYNC_DATA_IND_MSG_V01_MAX_MSG_LEN 6154
+extern struct qmi_elem_info wlfw_driver_async_data_ind_msg_v01_ei[];
+
+#endif

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio