qcacld-3.0: Add PLD layer
PLD stands for platform driver. It is a interface between CLD and
CNSS/ICNSS. It hides the CNSS/ICNSS APIs from CLD and provides a set
of common APIs.
Other modules should include pld_common.h if they want to call PLD
APIs.
CRs-Fixed: 979275
Change-Id: I3571fc70f502dc367c65f13b412cd5d37ee41d3c
diff --git a/Kbuild b/Kbuild
index d4da7c5..1031b35 100755
--- a/Kbuild
+++ b/Kbuild
@@ -847,6 +847,23 @@
WMA_OBJS += $(WMA_SRC_DIR)/wma_utils_ut.o
endif
+############## PLD ##########
+PLD_DIR := core/pld
+PLD_INC_DIR := $(PLD_DIR)/inc
+PLD_SRC_DIR := $(PLD_DIR)/src
+
+PLD_INC := -I$(WLAN_ROOT)/$(PLD_INC_DIR) \
+ -I$(WLAN_ROOT)/$(PLD_SRC_DIR)
+
+PLD_OBJS := $(PLD_SRC_DIR)/pld_common.o
+
+ifeq ($(CONFIG_PCI), y)
+PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie.o
+endif
+ifeq ($(CONFIG_ICNSS),y)
+PLD_OBJS += $(PLD_SRC_DIR)/pld_snoc.o
+endif
+
TARGET_INC := -I$(WLAN_ROOT)/target/inc
LINUX_INC := -Iinclude/linux
@@ -884,6 +901,8 @@
$(PTT_INC) \
$(WLAN_LOGGING_INC)
+INCS += $(PLD_INC)
+
ifeq ($(CONFIG_REMOVE_PKT_LOG), 0)
INCS += $(PKTLOG_INC)
endif
@@ -917,6 +936,8 @@
OBJS += $(NLINK_OBJS)
OBJS += $(PTT_OBJS)
+OBJS += $(PLD_OBJS)
+
ifeq ($(CONFIG_REMOVE_PKT_LOG), 0)
OBJS += $(PKTLOG_OBJS)
endif
diff --git a/core/pld/inc/pld_common.h b/core/pld/inc/pld_common.h
new file mode 100644
index 0000000..9345eaf
--- /dev/null
+++ b/core/pld/inc/pld_common.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __PLD_COMMON_H__
+#define __PLD_COMMON_H__
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+
+/**
+ * enum pld_bus_type - bus type
+ * @PLD_BUS_TYPE_NONE: invalid bus type, only return in error cases
+ * @PLD_BUS_TYPE_PCIE: PCIE bus
+ * @PLD_BUS_TYPE_SNOC: SNOC bus
+ */
+enum pld_bus_type {
+ PLD_BUS_TYPE_NONE = -1,
+ PLD_BUS_TYPE_PCIE = 0,
+ PLD_BUS_TYPE_SNOC
+};
+
+#define PLD_MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+
+/**
+ * enum pld_bus_width_type - bus bandwith
+ * @PLD_BUS_WIDTH_NONE: don't vote for bus bandwidth
+ * @PLD_BUS_WIDTH_LOW: vote for low bus bandwidth
+ * @PLD_BUS_WIDTH_MEDIUM: vote for medium bus bandwidth
+ * @PLD_BUS_WIDTH_HIGH: vote for high bus bandwidth
+ */
+enum pld_bus_width_type {
+ PLD_BUS_WIDTH_NONE,
+ PLD_BUS_WIDTH_LOW,
+ PLD_BUS_WIDTH_MEDIUM,
+ PLD_BUS_WIDTH_HIGH
+};
+
+#define PLD_MAX_FILE_NAME 20
+
+/**
+ * struct pld_fw_file - WLAN FW file names
+ * @image_file: WLAN FW image file
+ * @board_data: WLAN FW board data file
+ * @otp_data: WLAN FW OTP file
+ * @utf_file: WLAN FW UTF file
+ * @utf_board_data: WLAN FW UTF board data file
+ * @epping_file: WLAN FW EPPING mode file
+ * @evicted_data: WLAN FW evicted file
+ *
+ * pld_fw_files is used to store WLAN FW file names
+ */
+struct pld_fw_files {
+ char image_file[PLD_MAX_FILE_NAME];
+ char board_data[PLD_MAX_FILE_NAME];
+ char otp_data[PLD_MAX_FILE_NAME];
+ char utf_file[PLD_MAX_FILE_NAME];
+ char utf_board_data[PLD_MAX_FILE_NAME];
+ char epping_file[PLD_MAX_FILE_NAME];
+ char evicted_data[PLD_MAX_FILE_NAME];
+};
+
+/**
+ * struct pld_image_desc_info - FW image description
+ * @fw_addr: FW image address
+ * @fw_size: FW image size
+ * @bdata_addr: FW board data address
+ * @bdata_size: FW board data size
+ *
+ * pld_image_desc_info is used to store FW image description
+ * information.
+ */
+struct pld_image_desc_info {
+ dma_addr_t fw_addr;
+ u32 fw_size;
+ dma_addr_t bdata_addr;
+ u32 bdata_size;
+};
+
+#define PLD_CODESWAP_MAX_CODESEGS 16
+
+/**
+ * struct pld_codeswap_codeseg_info - code swap segment information
+ * @codeseg_total_bytes: total bytes of segments
+ * @num_codesegs: number of code segments
+ * @codeseg_size: code segment size
+ * @codeseg_size_log2: log2 of code segment size
+ * @codeseg_busaddr: array of addresses of each code segment
+ *
+ * pld_codeswap_codeseg_info is used to store code swap segment
+ * information.
+ */
+struct pld_codeswap_codeseg_info {
+ u32 codeseg_total_bytes;
+ u32 num_codesegs;
+ u32 codeseg_size;
+ u32 codeseg_size_log2;
+ void *codeseg_busaddr[PLD_CODESWAP_MAX_CODESEGS];
+};
+
+/**
+ * enum pld_platform_cap_flag - platform capability flag
+ * @PLD_HAS_EXTERNAL_SWREG: has external regulator
+ * @PLD_HAS_UART_ACCESS: has UART access
+ */
+enum pld_platform_cap_flag {
+ PLD_HAS_EXTERNAL_SWREG = 0x01,
+ PLD_HAS_UART_ACCESS = 0x02,
+};
+
+/**
+ * struct pld_platform_cap - platform capabilities
+ * @cap_flag: capabilities flag
+ *
+ * pld_platform_cap provides platform capabilities which are
+ * extracted from DTS.
+ */
+struct pld_platform_cap {
+ u32 cap_flag;
+};
+
+/**
+ * enum pld_driver_status - WLAN driver status
+ * @PLD_UNINITIALIZED: driver is uninitialized
+ * @PLD_INITIALIZED: driver is initialized
+ * @PLD_LOAD_UNLOADL: driver is in load-unload status
+ */
+enum pld_driver_status {
+ PLD_UNINITIALIZED,
+ PLD_INITIALIZED,
+ PLD_LOAD_UNLOAD
+};
+
+/**
+ * struct pld_ce_tgt_pipe_cfg - copy engine target pipe configuration
+ * @pipe_num: pipe number
+ * @pipe_dir: pipe direction
+ * @nentries: number of entries
+ * @nbytes_max: max number of bytes
+ * @flags: flags
+ * @reserved: reserved
+ *
+ * pld_ce_tgt_pipe_cfg is used to store copy engine target pipe
+ * configuration.
+ */
+struct pld_ce_tgt_pipe_cfg {
+ u32 pipe_num;
+ u32 pipe_dir;
+ u32 nentries;
+ u32 nbytes_max;
+ u32 flags;
+ u32 reserved;
+};
+
+/**
+ * struct pld_ce_svc_pipe_cfg - copy engine service pipe configuration
+ * @service_id: service ID
+ * @pipe_dir: pipe direction
+ * @pipe_num: pipe number
+ *
+ * pld_ce_svc_pipe_cfg is used to store copy engine service pipe
+ * configuration.
+ */
+struct pld_ce_svc_pipe_cfg {
+ u32 service_id;
+ u32 pipe_dir;
+ u32 pipe_num;
+};
+
+/**
+ * struct pld_shadow_reg_cfg - shadow register configuration
+ * @ce_id: copy engine ID
+ * @reg_offset: register offset
+ *
+ * pld_shadow_reg_cfg is used to store shadow register configuration.
+ */
+struct pld_shadow_reg_cfg {
+ u16 ce_id;
+ u16 reg_offset;
+};
+
+/**
+ * struct pld_wlan_enable_cfg - WLAN FW configuration
+ * @num_ce_tgt_cfg: number of CE target configuration
+ * @ce_tgt_cfg: CE target configuration
+ * @num_ce_svc_pipe_cfg: number of CE service configuration
+ * @ce_svc_cfg: CE service configuration
+ * @num_shadow_reg_cfg: number of shadow register configuration
+ * @shadow_reg_cfg: shadow register configuration
+ *
+ * pld_wlan_enable_cfg stores WLAN FW configurations. It will be
+ * passed to WLAN FW when WLAN host driver calls wlan_enable.
+ */
+struct pld_wlan_enable_cfg {
+ u32 num_ce_tgt_cfg;
+ struct pld_ce_tgt_pipe_cfg *ce_tgt_cfg;
+ u32 num_ce_svc_pipe_cfg;
+ struct pld_ce_svc_pipe_cfg *ce_svc_cfg;
+ u32 num_shadow_reg_cfg;
+ struct pld_shadow_reg_cfg *shadow_reg_cfg;
+};
+
+/**
+ * enum pld_driver_mode - WLAN host driver mode
+ * @PLD_MISSION: mission mode
+ * @PLD_FTM: FTM mode
+ * @PLD_EPPING: EPPING mode
+ * @PLD_WALTEST: WAL test mode, FW standalone test mode
+ * @PLD_OFF: OFF mode
+ */
+enum pld_driver_mode {
+ PLD_MISSION,
+ PLD_FTM,
+ PLD_EPPING,
+ PLD_WALTEST,
+ PLD_OFF
+};
+
+/**
+ * struct pld_soc_info - SOC information
+ * @v_addr: virtual address of preallocated memory
+ * @p_addr: physical address of preallcoated memory
+ * @version: version number
+ *
+ * pld_soc_info is used to store WLAN SOC information.
+ */
+struct pld_soc_info {
+ void __iomem *v_addr;
+ phys_addr_t p_addr;
+ u32 version;
+};
+
+/**
+ * struct pld_driver_ops - driver callback functions
+ * @probe: required operation, will be called when device is detected
+ * @remove: required operation, will be called when device is removed
+ * @shutdown: optional operation, will be called during SSR
+ * @reinit: optional operation, will be called during SSR
+ * @crash_shutdown: optional operation, will be called when a crash is
+ * detected
+ * @suspend: required operation, will be called for power management
+ * is enabled
+ * @resume: required operation, will be called for power management
+ * is enabled
+ * @modem_status: optional operation, will be called when platform driver
+ * sending modem power status to WLAN FW
+ */
+struct pld_driver_ops {
+ int (*probe)(struct device *dev,
+ enum pld_bus_type bus_type,
+ void *bdev, void *id);
+ void (*remove)(struct device *dev,
+ enum pld_bus_type bus_type);
+ void (*shutdown)(struct device *dev,
+ enum pld_bus_type bus_type);
+ int (*reinit)(struct device *dev,
+ enum pld_bus_type bus_type,
+ void *bdev, void *id);
+ void (*crash_shutdown)(struct device *dev,
+ enum pld_bus_type bus_type);
+ int (*suspend)(struct device *dev,
+ enum pld_bus_type bus_type,
+ pm_message_t state);
+ int (*resume)(struct device *dev,
+ enum pld_bus_type bus_type);
+ void (*modem_status)(struct device *dev,
+ enum pld_bus_type bus_type,
+ int state);
+};
+
+int pld_init(void);
+void pld_deinit(void);
+
+int pld_register_driver(struct pld_driver_ops *ops);
+void pld_unregister_driver(void);
+
+int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version);
+int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode);
+int pld_set_fw_debug_mode(struct device *dev, bool enablefwlog);
+int pld_get_fw_files_for_target(struct device *dev,
+ struct pld_fw_files *pfw_files,
+ u32 target_type, u32 target_version);
+int pld_get_fw_image(struct device *dev,
+ struct pld_image_desc_info *image_desc_info);
+void pld_is_pci_link_down(struct device *dev);
+int pld_pcie_shadow_control(struct device *dev, bool enable);
+int pld_get_codeswap_struct(struct device *dev,
+ struct pld_codeswap_codeseg_info *swap_seg);
+int pld_set_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list,
+ u16 ch_count);
+int pld_get_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list,
+ u16 *ch_count, u16 buf_len);
+int pld_wlan_set_dfs_nol(struct device *dev, void *info, u16 info_len);
+int pld_wlan_get_dfs_nol(struct device *dev, void *info, u16 info_len);
+int pld_wlan_pm_control(struct device *dev, bool vote);
+void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size);
+void pld_device_crashed(struct device *dev);
+void pld_device_self_recovery(struct device *dev);
+void pld_intr_notify_q6(struct device *dev);
+void pld_request_pm_qos(struct device *dev, u32 qos_val);
+void pld_remove_pm_qos(struct device *dev);
+int pld_request_bus_bandwidth(struct device *dev, int bandwidth);
+int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap);
+void pld_set_driver_status(struct device *dev, enum pld_driver_status status);
+int pld_get_bmi_setup(struct device *dev);
+int pld_get_sha_hash(struct device *dev, const u8 *data,
+ u32 data_len, u8 *hash_idx, u8 *out);
+void *pld_get_fw_ptr(struct device *dev);
+int pld_auto_suspend(struct device *dev);
+int pld_auto_resume(struct device *dev);
+
+int pld_ce_request_irq(struct device *dev, unsigned int ce_id,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long flags, const char *name, void *ctx);
+int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx);
+void pld_enable_irq(struct device *dev, unsigned int ce_id);
+void pld_disable_irq(struct device *dev, unsigned int ce_id);
+int pld_get_soc_info(struct device *dev, struct pld_soc_info *info);
+int pld_get_ce_id(struct device *dev, int irq);
+
+#endif
diff --git a/core/pld/src/pld_common.c b/core/pld/src/pld_common.c
new file mode 100644
index 0000000..902c210
--- /dev/null
+++ b/core/pld/src/pld_common.c
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#define pr_fmt(fmt) "wlan_pld:%s:%d:: " fmt, __func__, __LINE__
+
+#include <linux/printk.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#endif
+#ifdef CONFIG_ICNSS
+#include <soc/qcom/icnss.h>
+#endif
+
+#include "pld_pcie.h"
+#include "pld_snoc.h"
+#include "pld_common.h"
+#include "pld_internal.h"
+
+#define PLD_PCIE_REGISTERED BIT(0)
+#define PLD_SNOC_REGISTERED BIT(1)
+
+static struct pld_context *pld_ctx;
+
+/**
+ * pld_init() - Initialize PLD module
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_init(void)
+{
+ struct pld_context *pld_context;
+
+ pld_context = kzalloc(sizeof(*pld_context), GFP_KERNEL);
+ if (!pld_context)
+ return -ENOMEM;
+
+ spin_lock_init(&pld_context->pld_lock);
+
+ INIT_LIST_HEAD(&pld_context->dev_list);
+
+ pld_ctx = pld_context;
+
+ return 0;
+}
+
+/**
+ * pld_deinit() - Uninitialize PLD module
+ *
+ * Return: void
+ */
+void pld_deinit(void)
+{
+ struct dev_node *dev_node;
+ struct pld_context *pld_context;
+ unsigned long flags;
+
+ pld_context = pld_ctx;
+ if (!pld_context) {
+ pld_ctx = NULL;
+ return;
+ }
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ while (!list_empty(&pld_context->dev_list)) {
+ dev_node = list_first_entry(&pld_context->dev_list,
+ struct dev_node, list);
+ list_del(&dev_node->list);
+ kfree(dev_node);
+ }
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ kfree(pld_context);
+
+ pld_ctx = NULL;
+}
+
+/**
+ * pld_get_global_context() - Get global context of PLD
+ *
+ * Return: PLD global context
+ */
+struct pld_context *pld_get_global_context(void)
+{
+ return pld_ctx;
+}
+
+/**
+ * pld_get_bus_type() - Bus type of the device
+ * @dev: device
+ *
+ * Return: PLD bus type
+ */
+enum pld_bus_type pld_get_bus_type(struct device *dev)
+{
+ struct pld_context *pld_context;
+ struct dev_node *dev_node;
+ unsigned long flags;
+
+ pld_context = pld_get_global_context();
+
+ if (dev == NULL || pld_context == NULL) {
+ pr_err("Invalid info: dev %p, context %p\n",
+ dev, pld_context);
+ return PLD_BUS_TYPE_NONE;
+ }
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ list_for_each_entry(dev_node, &pld_context->dev_list, list) {
+ if (dev_node->dev == dev) {
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+ return dev_node->bus_type;
+ }
+ }
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ return PLD_BUS_TYPE_NONE;
+}
+
+/**
+ * pld_register_driver() - Register driver to kernel
+ * @ops: Callback functions that will be registered to kernel
+ *
+ * This function should be called when other modules want to
+ * register platform driver callback functions to kernel. The
+ * probe() is expected to be called after registration if the
+ * device is online.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_register_driver(struct pld_driver_ops *ops)
+{
+ int ret = 0;
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+
+ if (pld_context == NULL) {
+ pr_err("global context is NULL\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (pld_context->ops) {
+ pr_err("driver already registered\n");
+ ret = -EEXIST;
+ goto out;
+ }
+
+ if (!ops || !ops->probe || !ops->remove ||
+ !ops->suspend || !ops->resume) {
+ pr_err("Required callback functions are missing\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pld_context->ops = ops;
+
+ if (0 == pld_pcie_register_driver())
+ pld_context->pld_driver_state |= PLD_PCIE_REGISTERED;
+ if (0 == pld_snoc_register_driver())
+ pld_context->pld_driver_state |= PLD_SNOC_REGISTERED;
+
+ if (0 == pld_context->pld_driver_state) {
+ pr_err("All driver falied to register\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * pld_unregister_driver() - Unregister driver to kernel
+ *
+ * This function should be called when other modules want to
+ * unregister callback functions from kernel. The remove() is
+ * expected to be called after registration.
+ *
+ * Return: void
+ */
+void pld_unregister_driver(void)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+
+ if (pld_context == NULL) {
+ pr_err("global context is NULL\n");
+ return;
+ }
+
+ if (pld_context->ops == NULL) {
+ pr_err("driver not registered\n");
+ return;
+ }
+
+ pld_pcie_unregister_driver();
+ pld_snoc_unregister_driver();
+
+ pld_context->pld_driver_state = 0;
+
+ pld_context->ops = NULL;
+}
+
+/**
+ * pld_wlan_enable() - Enable WLAN
+ * @dev: device
+ * @config: WLAN configuration data
+ * @mode: WLAN mode
+ * @host_version: host software version
+ *
+ * This function enables WLAN FW. It passed WLAN configuration data,
+ * WLAN mode and host software version to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_wlan_enable(config, mode, host_version);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ ret = pld_snoc_wlan_enable(config, mode, host_version);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_wlan_disable() - Disable WLAN
+ * @dev: device
+ * @mode: WLAN mode
+ *
+ * This function disables WLAN FW. It passes WLAN mode to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_wlan_disable(mode);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ ret = pld_snoc_wlan_disable(mode);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_set_fw_debug_mode() - Set FW debug mode
+ * @dev: device
+ * @enablefwlog: 0 for QXDM, 1 for WMI
+ *
+ * Switch Fw debug mode between DIAG logging and WMI logging.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_set_fw_debug_mode(struct device *dev, bool enablefwlog)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_set_fw_debug_mode(enablefwlog);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_fw_files_for_target() - Get FW file names
+ * @dev: device
+ * @pfw_files: buffer for FW file names
+ * @target_type: target type
+ * @target_version: target version
+ *
+ * Return target specific FW file names to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_fw_files_for_target(struct device *dev,
+ struct pld_fw_files *pfw_files,
+ u32 target_type, u32 target_version)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_get_fw_files_for_target(pfw_files,
+ target_type, target_version);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_fw_image() - Get FW image descriptor
+ * @dev: device
+ * @image_desc_info: buffer for image descriptor
+ *
+ * Return FW image descriptor to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_fw_image(struct device *dev,
+ struct pld_image_desc_info *image_desc_info)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_get_fw_image(image_desc_info);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_is_pci_link_down() - Notification for pci link down event
+ * @dev: device
+ *
+ * Notify platform that pci link is down.
+ *
+ * Return: void
+ */
+void pld_is_pci_link_down(struct device *dev)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_wlan_pci_link_down();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_pcie_shadow_control() - Control pci shadow registers
+ * @dev: device
+ * @enable: 0 for disable, 1 for enable
+ *
+ * This function is for suspend/resume. It can control if we
+ * use pci shadow registers (for saving config space) or not.
+ * During suspend we disable it to avoid config space corruption.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_shadow_control(struct device *dev, bool enable)
+{
+ int ret = 0;
+
+ /* cnss_shadow_control is not supported on BF64.0.3 kernel yet
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_shadow_control(enable);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ */
+ return ret;
+}
+
+/**
+ * pld_get_codeswap_struct() - Get codeswap structure
+ * @dev: device
+ * @swap_seg: buffer to codeswap information
+ *
+ * Return codeswap structure information to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_codeswap_struct(struct device *dev,
+ struct pld_codeswap_codeseg_info *swap_seg)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_get_codeswap_struct(swap_seg);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_set_wlan_unsafe_channel() - Set unsafe channel
+ * @dev: device
+ * @unsafe_ch_list: unsafe channel list
+ * @ch_count: number of channel
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_set_wlan_unsafe_channel(struct device *dev,
+ u16 *unsafe_ch_list, u16 ch_count)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_set_wlan_unsafe_channel(unsafe_ch_list,
+ ch_count);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_wlan_unsafe_channel() - Get unsafe channel
+ * @dev: device
+ * @unsafe_ch_list: buffer to unsafe channel list
+ * @ch_count: number of channel
+ * @buf_len: buffer length
+ *
+ * Return WLAN unsafe channel to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list,
+ u16 *ch_count, u16 buf_len)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_get_wlan_unsafe_channel(unsafe_ch_list,
+ ch_count, buf_len);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_wlan_set_dfs_nol() - Set DFS info
+ * @dev: device
+ * @info: DFS info
+ * @info_len: info length
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_wlan_set_dfs_nol(struct device *dev, void *info, u16 info_len)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_wlan_set_dfs_nol(info, info_len);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_wlan_get_dfs_nol() - Get DFS info
+ * @dev: device
+ * @info: buffer to DFS info
+ * @info_len: info length
+ *
+ * Return DFS info to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_wlan_get_dfs_nol(struct device *dev, void *info, u16 info_len)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_wlan_get_dfs_nol(info, info_len);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_wlan_pm_control() - WLAN PM control on PCIE
+ * @dev: device
+ * @vote: 0 for enable PCIE PC, 1 for disable PCIE PC
+ *
+ * This is for PCIE power collaps control during suspend/resume.
+ * When PCIE power collaps is disabled, WLAN FW can access memory
+ * through PCIE when system is suspended.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_wlan_pm_control(struct device *dev, bool vote)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_wlan_pm_control(vote);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_virt_ramdump_mem() - Get virtual ramdump memory
+ * @dev: device
+ * @size: buffer to virtual memory size
+ *
+ * Return: virtual ramdump memory address
+ */
+void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+ void *mem = NULL;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ mem = cnss_get_virt_ramdump_mem(size);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+
+ return mem;
+}
+
+/**
+ * pld_device_crashed() - Notification for device crash event
+ * @dev: device
+ *
+ * Notify subsystem a device crashed event. A subsystem restart
+ * is expected to happen after calling this function.
+ *
+ * Return: void
+ */
+void pld_device_crashed(struct device *dev)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_device_crashed();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_device_self_recovery() - Device self recovery
+ * @dev: device
+ *
+ * Return: void
+ */
+void pld_device_self_recovery(struct device *dev)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_device_self_recovery();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_intr_notify_q6() - Notify Q6 FW interrupts
+ * @dev: device
+ *
+ * Notify Q6 that a FW interrupt is triggered.
+ *
+ * Return: void
+ */
+void pld_intr_notify_q6(struct device *dev)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_intr_notify_q6();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_request_pm_qos() - Request system PM
+ * @dev: device
+ * @qos_val: request value
+ *
+ * It votes for the value of aggregate QoS expectations.
+ *
+ * Return: void
+ */
+void pld_request_pm_qos(struct device *dev, u32 qos_val)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_request_pm_qos(qos_val);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_remove_pm_qos() - Remove system PM
+ * @dev: device
+ *
+ * Remove the vote request for Qos expectations.
+ *
+ * Return: void
+ */
+void pld_remove_pm_qos(struct device *dev)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ cnss_remove_pm_qos();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_request_bus_bandwidth() - Request bus bandwidth
+ * @dev: device
+ * @bandwidth: bus bandwidth
+ *
+ * Votes for HIGH/MEDIUM/LOW bus bandwidth.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_request_bus_bandwidth(bandwidth);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_platform_cap() - Get platform capabilities
+ * @dev: device
+ * @cap: buffer to the capabilities
+ *
+ * Return capabilities to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_get_platform_cap(cap);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_set_driver_status() - Set driver status
+ * @dev: device
+ * @status: driver status
+ *
+ * Return: void
+ */
+void pld_set_driver_status(struct device *dev, enum pld_driver_status status)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ pld_pcie_set_driver_status(status);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_get_bmi_setup() - Get BMI setup
+ * @dev: device
+ *
+ * BMI read/write test should be run if BMI test is enabled.
+ *
+ * Return: BMI test setup
+ */
+int pld_get_bmi_setup(struct device *dev)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_get_bmi_setup();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_sha_hash() - Get sha hash number
+ * @dev: device
+ * @data: input data
+ * @data_len: data length
+ * @hash_idx: hash index
+ * @out: output buffer
+ *
+ * Return computed hash to the out buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_sha_hash(struct device *dev, const u8 *data,
+ u32 data_len, u8 *hash_idx, u8 *out)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_get_sha_hash(data, data_len,
+ hash_idx, out);
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_fw_ptr() - Get secure FW memory address
+ * @dev: device
+ *
+ * Return: secure memory address
+ */
+void *pld_get_fw_ptr(struct device *dev)
+{
+ void *ptr = NULL;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ptr = cnss_get_fw_ptr();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+
+ return ptr;
+}
+
+/**
+ * pld_auto_suspend() - Auto suspend
+ * @dev: device
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_auto_suspend(struct device *dev)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_auto_suspend();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_auto_resume() - Auto resume
+ * @dev: device
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_auto_resume(struct device *dev)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_PCIE:
+ ret = cnss_auto_resume();
+ break;
+ case PLD_BUS_TYPE_SNOC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_ce_request_irq() - Register IRQ for CE
+ * @dev: device
+ * @ce_id: CE number
+ * @handler: IRQ callback function
+ * @flags: IRQ flags
+ * @name: IRQ name
+ * @ctx: IRQ context
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_ce_request_irq(struct device *dev, unsigned int ce_id,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long flags, const char *name, void *ctx)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ ret = icnss_ce_request_irq(ce_id, handler, flags, name, ctx);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_ce_free_irq() - Free IRQ for CE
+ * @dev: device
+ * @ce_id: CE number
+ * @ctx: IRQ context
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ ret = icnss_ce_free_irq(ce_id, ctx);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_enable_irq() - Enable IRQ for CE
+ * @dev: device
+ * @ce_id: CE number
+ *
+ * Return: void
+ */
+void pld_enable_irq(struct device *dev, unsigned int ce_id)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ icnss_enable_irq(ce_id);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_disable_irq() - Disable IRQ for CE
+ * @dev: device
+ * @ce_id: CE number
+ *
+ * Return: void
+ */
+void pld_disable_irq(struct device *dev, unsigned int ce_id)
+{
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ icnss_disable_irq(ce_id);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ break;
+ default:
+ pr_err("Invalid device type\n");
+ break;
+ }
+}
+
+/**
+ * pld_get_soc_info() - Get SOC information
+ * @dev: device
+ * @info: buffer to SOC information
+ *
+ * Return SOC info to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_get_soc_info(struct device *dev, struct pld_soc_info *info)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ ret = pld_snoc_get_soc_info(info);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pld_get_ce_id() - Get CE number for the provided IRQ
+ * @dev: device
+ * @irq: IRQ number
+ *
+ * Return: CE number
+ */
+int pld_get_ce_id(struct device *dev, int irq)
+{
+ int ret = 0;
+
+ switch (pld_get_bus_type(dev)) {
+ case PLD_BUS_TYPE_SNOC:
+ ret = icnss_get_ce_id(irq);
+ break;
+ case PLD_BUS_TYPE_PCIE:
+ ret = pld_pcie_get_ce_id(irq);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
diff --git a/core/pld/src/pld_internal.h b/core/pld/src/pld_internal.h
new file mode 100644
index 0000000..3619848
--- /dev/null
+++ b/core/pld/src/pld_internal.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __PLD_COMMON_I_H__
+#define __PLD_COMMON_I_H__
+
+struct dev_node {
+ struct device *dev;
+ struct list_head list;
+ enum pld_bus_type bus_type;
+};
+
+struct pld_context {
+ struct pld_driver_ops *ops;
+ spinlock_t pld_lock;
+ struct list_head dev_list;
+ uint32_t pld_driver_state;
+};
+
+struct pld_context *pld_get_global_context(void);
+
+#endif
diff --git a/core/pld/src/pld_pcie.c b/core/pld/src/pld_pcie.c
new file mode 100644
index 0000000..ca77780
--- /dev/null
+++ b/core/pld/src/pld_pcie.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_CNSS
+#include <net/cnss.h>
+#endif
+
+#include "pld_common.h"
+#include "pld_internal.h"
+
+#ifdef CONFIG_PCI
+
+#ifdef QCA_WIFI_3_0_ADRASTEA
+#define CE_COUNT_MAX 12
+#else
+#define CE_COUNT_MAX 8
+#endif
+
+/**
+ * pld_pcie_probe() - Probe function for PCIE platform driver
+ * @pdev: PCIE device
+ * @id: PCIE device ID table
+ *
+ * The probe function will be called when PCIE device provided
+ * in the ID table is detected.
+ *
+ * Return: int
+ */
+static int pld_pcie_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct pld_context *pld_context;
+ unsigned long flags;
+ struct dev_node *dev_node;
+ int ret = 0;
+
+ pld_context = pld_get_global_context();
+ if (!pld_context) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL);
+ if (dev_node == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev_node->dev = &pdev->dev;
+ dev_node->bus_type = PLD_BUS_TYPE_PCIE;
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ list_add_tail(&dev_node->list, &pld_context->dev_list);
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ return pld_context->ops->probe(&pdev->dev,
+ PLD_BUS_TYPE_PCIE, pdev, (void *)id);
+
+out:
+ return ret;
+}
+
+
+/**
+ * pld_pcie_remove() - Remove function for PCIE device
+ * @pdev: PCIE device
+ *
+ * The remove function will be called when PCIE device is disconnected
+ *
+ * Return: void
+ */
+static void pld_pcie_remove(struct pci_dev *pdev)
+{
+ struct pld_context *pld_context;
+ unsigned long flags;
+ struct dev_node *dev_node, *tmp;
+
+ pld_context = pld_get_global_context();
+
+ if (!pld_context)
+ return;
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ list_for_each_entry_safe(dev_node, tmp, &pld_context->dev_list, list) {
+ if (dev_node->dev == &pdev->dev) {
+ list_del(&dev_node->list);
+ kfree(dev_node);
+ }
+ }
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
+}
+
+#ifdef CONFIG_CNSS
+/**
+ * pld_pcie_reinit() - SSR re-initialize function for PCIE device
+ * @pdev: PCIE device
+ * @id: PCIE device ID
+ *
+ * During subsystem restart(SSR), this function will be called to
+ * re-initialize PCIE device.
+ *
+ * Return: int
+ */
+static int pld_pcie_reinit(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->reinit)
+ return pld_context->ops->reinit(&pdev->dev,
+ PLD_BUS_TYPE_PCIE, pdev, (void *)id);
+
+ return -ENODEV;
+}
+
+/**
+ * pld_pcie_shutdown() - SSR shutdown function for PCIE device
+ * @pdev: PCIE device
+ *
+ * During SSR, this function will be called to shutdown PCIE device.
+ *
+ * Return: void
+ */
+static void pld_pcie_shutdown(struct pci_dev *pdev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->shutdown)
+ pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
+}
+
+/**
+ * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
+ * @pdev: PCIE device
+ *
+ * This function will be called when a crash is detected, it will shutdown
+ * the PCIE device.
+ *
+ * Return: void
+ */
+static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->crash_shutdown)
+ pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
+}
+
+/**
+ * pld_pcie_notify_handler() - Modem state notification callback function
+ * @pdev: PCIE device
+ * @state: modem power state
+ *
+ * This function will be called when there's a modem power state change.
+ *
+ * Return: void
+ */
+static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->modem_status)
+ pld_context->ops->modem_status(&pdev->dev,
+ PLD_BUS_TYPE_PCIE, state);
+}
+#endif
+
+/**
+ * pld_pcie_suspend() - Suspend callback function for power management
+ * @pdev: PCIE device
+ * @state: power state
+ *
+ * This function is to suspend the PCIE device when power management is
+ * enabled.
+ *
+ * Return: void
+ */
+static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ return pld_context->ops->suspend(&pdev->dev,
+ PLD_BUS_TYPE_PCIE, state);
+}
+
+/**
+ * pld_pcie_resume() - Resume callback function for power management
+ * @pdev: PCIE device
+ *
+ * This function is to resume the PCIE device when power management is
+ * enabled.
+ *
+ * Return: void
+ */
+static int pld_pcie_resume(struct pci_dev *pdev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
+}
+
+static struct pci_device_id pld_pcie_id_table[] = {
+ { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
+ { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
+ { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
+ { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
+ { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
+ { 0 }
+};
+
+#ifdef CONFIG_CNSS
+struct cnss_wlan_driver pld_pcie_ops = {
+ .name = "pld_pcie",
+ .id_table = pld_pcie_id_table,
+ .probe = pld_pcie_probe,
+ .remove = pld_pcie_remove,
+ .reinit = pld_pcie_reinit,
+ .shutdown = pld_pcie_shutdown,
+ .crash_shutdown = pld_pcie_crash_shutdown,
+ .modem_status = pld_pcie_notify_handler,
+#ifdef CONFIG_PM
+ .suspend = pld_pcie_suspend,
+ .resume = pld_pcie_resume,
+#endif
+};
+
+/**
+ * pld_pcie_register_driver() - Register PCIE device callback functions
+ *
+ * Return: int
+ */
+int pld_pcie_register_driver(void)
+{
+ return cnss_wlan_register_driver(&pld_pcie_ops);
+}
+
+/**
+ * pld_pcie_unregister_driver() - Unregister PCIE device callback functions
+ *
+ * Return: void
+ */
+void pld_pcie_unregister_driver(void)
+{
+ cnss_wlan_unregister_driver(&pld_pcie_ops);
+}
+#else
+struct pci_driver pld_pcie_ops = {
+ .name = "pld_pcie",
+ .id_table = pld_pcie_id_table,
+ .probe = pld_pcie_probe,
+ .remove = pld_pcie_remove,
+#ifdef CONFIG_PM
+ .suspend = pld_pcie_suspend,
+ .resume = pld_pcie_resume,
+#endif
+};
+
+int pld_pcie_register_driver(void)
+{
+ return pci_register_driver(&pld_pcie_ops);
+}
+
+void pld_pcie_unregister_driver(void)
+{
+ pci_unregister_driver(&pld_pcie_ops);
+}
+#endif
+
+/**
+ * pld_pcie_get_ce_id() - Get CE number for the provided IRQ
+ * @irq: IRQ number
+ *
+ * Return: CE number
+ */
+int pld_pcie_get_ce_id(int irq)
+{
+ int ce_id = irq - 100;
+ if (ce_id < CE_COUNT_MAX && ce_id >= 0)
+ return ce_id;
+
+ return -EINVAL;
+}
+
+#ifdef CONFIG_CNSS
+#ifdef QCA_WIFI_3_0_ADRASTEA
+/**
+ * pld_pcie_wlan_enable() - Enable WLAN
+ * @config: WLAN configuration data
+ * @mode: WLAN mode
+ * @host_version: host software version
+ *
+ * This function enables WLAN FW. It passed WLAN configuration data,
+ * WLAN mode and host software version to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version)
+{
+ struct cnss_wlan_enable_cfg cfg;
+ enum cnss_driver_mode cnss_mode;
+
+ cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
+ cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
+ config->ce_tgt_cfg;
+ cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
+ cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
+ config->ce_svc_cfg;
+ cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
+ cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
+ config->shadow_reg_cfg;
+
+ switch (mode) {
+ case PLD_FTM:
+ cnss_mode = CNSS_FTM;
+ break;
+ case PLD_EPPING:
+ cnss_mode = CNSS_EPPING;
+ break;
+ default:
+ cnss_mode = CNSS_MISSION;
+ break;
+ }
+ return cnss_wlan_enable(&cfg, cnss_mode, host_version);
+}
+
+/**
+ * pld_pcie_wlan_disable() - Disable WLAN
+ * @mode: WLAN mode
+ *
+ * This function disables WLAN FW. It passes WLAN mode to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_wlan_disable(enum pld_driver_mode mode)
+{
+ return cnss_wlan_disable(CNSS_OFF);
+}
+
+/**
+ * pld_pcie_set_fw_debug_mode() - Set FW debug mode
+ * @mode: 0 for QXDM, 1 for WMI
+ *
+ * Switch Fw debug mode between DIAG logging and WMI logging.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_set_fw_debug_mode(bool mode)
+{
+ return cnss_set_fw_debug_mode(mode);
+}
+#endif
+
+/**
+ * pld_pcie_get_fw_files_for_target() - Get FW file names
+ * @pfw_files: buffer for FW file names
+ * @target_type: target type
+ * @target_version: target version
+ *
+ * Return target specific FW file names to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files,
+ u32 target_type, u32 target_version)
+{
+ int ret = 0;
+ struct cnss_fw_files cnss_fw_files;
+
+ if (pfw_files == NULL)
+ return -ENODEV;
+
+ ret = cnss_get_fw_files_for_target(&cnss_fw_files,
+ target_type, target_version);
+ if (0 != ret)
+ return ret;
+
+ memcpy(pfw_files, &cnss_fw_files, sizeof(*pfw_files));
+ return 0;
+}
+
+/**
+ * pld_pcie_get_fw_image() - Get FW image descriptor
+ * @image_desc_info: buffer for image descriptor
+ *
+ * Return FW image descriptor to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_get_fw_image(struct pld_image_desc_info *image_desc_info)
+{
+ int ret = 0;
+ struct image_desc_info cnss_image_desc_info;
+
+ if (image_desc_info == NULL)
+ return -ENODEV;
+
+ ret = cnss_get_fw_image(&cnss_image_desc_info);
+ if (0 != ret)
+ return ret;
+
+ memcpy(image_desc_info, &cnss_image_desc_info,
+ sizeof(*image_desc_info));
+ return 0;
+}
+
+/**
+ * pld_pcie_get_codeswap_struct() - Get codeswap structure
+ * @swap_seg: buffer to codeswap information
+ *
+ * Return codeswap structure information to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_get_codeswap_struct(struct pld_codeswap_codeseg_info *swap_seg)
+{
+ int ret = 0;
+ struct codeswap_codeseg_info cnss_swap_seg;
+
+ if (swap_seg == NULL)
+ return -ENODEV;
+
+ ret = cnss_get_codeswap_struct(&cnss_swap_seg);
+ if (0 != ret)
+ return ret;
+
+ memcpy(swap_seg, &cnss_swap_seg, sizeof(*swap_seg));
+ return 0;
+}
+
+/**
+ * pld_pcie_get_platform_cap() - Get platform capabilities
+ * @cap: buffer to the capabilities
+ *
+ * Return capabilities to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_pcie_get_platform_cap(struct pld_platform_cap *cap)
+{
+ int ret = 0;
+ struct cnss_platform_cap cnss_cap;
+
+ if (cap == NULL)
+ return -ENODEV;
+
+ ret = cnss_get_platform_cap(&cnss_cap);
+ if (0 != ret)
+ return ret;
+
+ memcpy(cap, &cnss_cap, sizeof(*cap));
+ return 0;
+}
+
+/**
+ * pld_pcie_set_driver_status() - Set driver status
+ * @status: driver status
+ *
+ * Return: void
+ */
+void pld_pcie_set_driver_status(enum pld_driver_status status)
+{
+ enum cnss_driver_status cnss_status;
+
+ switch (status) {
+ case PLD_UNINITIALIZED:
+ cnss_status = CNSS_UNINITIALIZED;
+ break;
+ case PLD_INITIALIZED:
+ cnss_status = CNSS_INITIALIZED;
+ break;
+ default:
+ cnss_status = CNSS_LOAD_UNLOAD;
+ break;
+ }
+ cnss_set_driver_status(cnss_status);
+}
+#endif
+
+#endif
diff --git a/core/pld/src/pld_pcie.h b/core/pld/src/pld_pcie.h
new file mode 100644
index 0000000..16d022b
--- /dev/null
+++ b/core/pld/src/pld_pcie.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __PLD_PCIE_H__
+#define __PLD_PCIE_H__
+
+#include "pld_common.h"
+
+#ifndef CONFIG_PCI
+static inline int pld_pcie_register_driver(void)
+{
+ return 0;
+}
+
+static inline void pld_pcie_unregister_driver(void)
+{
+ return;
+}
+
+static inline int pld_pcie_get_ce_id(int irq)
+{
+ return 0;
+}
+#else
+int pld_pcie_register_driver(void);
+void pld_pcie_unregister_driver(void);
+int pld_pcie_get_ce_id(int irq);
+#endif
+
+#if (!defined(CONFIG_CNSS)) || (!defined(QCA_WIFI_3_0_ADRASTEA))
+static inline int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version)
+{
+ return 0;
+}
+static inline int pld_pcie_wlan_disable(enum pld_driver_mode mode)
+{
+ return 0;
+}
+static inline int pld_pcie_set_fw_debug_mode(bool enablefwlog)
+{
+ return 0;
+}
+static inline void cnss_intr_notify_q6(void)
+{
+ return;
+}
+#else
+int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version);
+int pld_pcie_wlan_disable(enum pld_driver_mode mode);
+int pld_pcie_set_fw_debug_mode(bool enablefwlog);
+#endif
+
+#if (!defined(CONFIG_CNSS)) || (!defined(CONFIG_CNSS_SECURE_FW))
+static inline int cnss_get_sha_hash(const u8 *data,
+ u32 data_len, u8 *hash_idx, u8 *out)
+{
+ return 0;
+}
+static inline void *cnss_get_fw_ptr(void)
+{
+ return NULL;
+}
+#endif
+
+#ifndef CONFIG_CNSS
+static inline int
+pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files,
+ u32 target_type, u32 target_version)
+{
+ return 0;
+}
+static inline int
+pld_pcie_get_fw_image(struct pld_image_desc_info *image_desc_info)
+{
+ return 0;
+}
+static inline void cnss_wlan_pci_link_down(void)
+{
+ return;
+}
+static inline int cnss_pcie_shadow_control(bool enable)
+{
+ return 0;
+}
+static inline int
+pld_pcie_get_codeswap_struct(struct pld_codeswap_codeseg_info *swap_seg)
+{
+ return 0;
+}
+static inline int
+cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+ return 0;
+}
+static inline int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
+ u16 *ch_count, u16 buf_len)
+{
+ return 0;
+}
+static inline int cnss_wlan_set_dfs_nol(void *info, u16 info_len)
+{
+ return 0;
+}
+static inline int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+ return 0;
+}
+static inline int cnss_wlan_pm_control(bool vote)
+{
+ return 0;
+}
+static inline void *cnss_get_virt_ramdump_mem(unsigned long *size)
+{
+ return NULL;
+}
+static inline void cnss_device_crashed(void)
+{
+ return;
+}
+static inline void cnss_device_self_recovery(void)
+{
+ return;
+}
+static inline void cnss_request_pm_qos(u32 qos_val)
+{
+ return;
+}
+static inline void cnss_remove_pm_qos(void)
+{
+ return;
+}
+static inline int cnss_request_bus_bandwidth(int bandwidth)
+{
+ return 0;
+}
+static inline int pld_pcie_get_platform_cap(struct pld_platform_cap *cap)
+{
+ return 0;
+}
+static inline void pld_pcie_set_driver_status(enum pld_driver_status status)
+{
+ return;
+}
+static inline int cnss_get_bmi_setup(void)
+{
+ return 0;
+}
+static inline int cnss_auto_suspend(void)
+{
+ return 0;
+}
+static inline int cnss_auto_resume(void)
+{
+ return 0;
+}
+#else
+int pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files,
+ u32 target_type, u32 target_version);
+int pld_pcie_get_fw_image(struct pld_image_desc_info *image_desc_info);
+int pld_pcie_get_codeswap_struct(struct pld_codeswap_codeseg_info *swap_seg);
+int pld_pcie_get_platform_cap(struct pld_platform_cap *cap);
+void pld_pcie_set_driver_status(enum pld_driver_status status);
+#endif
+
+#endif
diff --git a/core/pld/src/pld_snoc.c b/core/pld/src/pld_snoc.c
new file mode 100644
index 0000000..40cee70
--- /dev/null
+++ b/core/pld/src/pld_snoc.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_ICNSS
+#include <soc/qcom/icnss.h>
+#endif
+
+#include "pld_common.h"
+#include "pld_internal.h"
+
+#ifdef CONFIG_ICNSS
+/**
+ * pld_snoc_probe() - Probe function for platform driver
+ * @dev: device
+ *
+ * The probe function will be called when platform device
+ * is detected.
+ *
+ * Return: int
+ */
+static int pld_snoc_probe(struct device *dev)
+{
+ struct pld_context *pld_context;
+ unsigned long flags;
+ struct dev_node *dev_node;
+ int ret = 0;
+
+ pld_context = pld_get_global_context();
+ if (!pld_context) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL);
+ if (dev_node == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev_node->dev = dev;
+ dev_node->bus_type = PLD_BUS_TYPE_SNOC;
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ list_add_tail(&dev_node->list, &pld_context->dev_list);
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ return pld_context->ops->probe(dev, PLD_BUS_TYPE_SNOC,
+ NULL, NULL);
+
+out:
+ return ret;
+}
+
+/**
+ * pld_snoc_remove() - Remove function for platform device
+ * @dev: device
+ *
+ * The remove function will be called when platform device
+ * is disconnected
+ *
+ * Return: void
+ */
+static void pld_snoc_remove(struct device *dev)
+{
+ struct pld_context *pld_context;
+ unsigned long flags;
+ struct dev_node *dev_node, *tmp;
+
+ pld_context = pld_get_global_context();
+
+ if (!pld_context)
+ return;
+
+ spin_lock_irqsave(&pld_context->pld_lock, flags);
+ list_for_each_entry_safe(dev_node, tmp, &pld_context->dev_list, list) {
+ if (dev_node->dev == dev) {
+ list_del(&dev_node->list);
+ kfree(dev_node);
+ }
+ }
+ spin_unlock_irqrestore(&pld_context->pld_lock, flags);
+
+ pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC);
+}
+
+/**
+ * pld_snoc_reinit() - SSR re-initialize function for platform device
+ * @dev: device
+ *
+ * During subsystem restart(SSR), this function will be called to
+ * re-initialize platform device.
+ *
+ * Return: int
+ */
+static int pld_snoc_reinit(struct device *dev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->reinit)
+ return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SNOC,
+ NULL, NULL);
+
+ return -ENODEV;
+}
+
+/**
+ * pld_snoc_shutdown() - SSR shutdown function for platform device
+ * @dev: device
+ *
+ * During SSR, this function will be called to shutdown platform device.
+ *
+ * Return: void
+ */
+static void pld_snoc_shutdown(struct device *dev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->shutdown)
+ pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SNOC);
+}
+
+/**
+ * pld_snoc_crash_shutdown() - Crash shutdown function for platform device
+ * @dev: device
+ *
+ * This function will be called when a crash is detected, it will shutdown
+ * platform device.
+ *
+ * Return: void
+ */
+static void pld_snoc_crash_shutdown(void *dev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ if (pld_context->ops->crash_shutdown)
+ pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SNOC);
+}
+
+/**
+ * pld_snoc_suspend() - Suspend callback function for power management
+ * @dev: device
+ * @state: power state
+ *
+ * This function is to suspend the platform device when power management
+ * is enabled.
+ *
+ * Return: void
+ */
+static int pld_snoc_suspend(struct device *dev, pm_message_t state)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ return pld_context->ops->suspend(dev, PLD_BUS_TYPE_SNOC, state);
+}
+
+/**
+ * pld_snoc_resume() - Resume callback function for power management
+ * @pdev: device
+ *
+ * This function is to resume the platform device when power management
+ * is enabled.
+ *
+ * Return: void
+ */
+static int pld_snoc_resume(struct device *dev)
+{
+ struct pld_context *pld_context;
+
+ pld_context = pld_get_global_context();
+ return pld_context->ops->resume(dev, PLD_BUS_TYPE_SNOC);
+}
+
+struct icnss_driver_ops pld_snoc_ops = {
+ .name = "pld_snoc",
+ .probe = pld_snoc_probe,
+ .remove = pld_snoc_remove,
+ .shutdown = pld_snoc_shutdown,
+ .reinit = pld_snoc_reinit,
+ .crash_shutdown = pld_snoc_crash_shutdown,
+ .suspend = pld_snoc_suspend,
+ .resume = pld_snoc_resume,
+};
+
+/**
+ * pld_snoc_register_driver() - Register platform device callback functions
+ *
+ * Return: int
+ */
+int pld_snoc_register_driver(void)
+{
+ return icnss_register_driver(&pld_snoc_ops);
+}
+
+/**
+ * pld_snoc_unregister_driver() - Unregister platform device callback functions
+ *
+ * Return: void
+ */
+void pld_snoc_unregister_driver(void)
+{
+ icnss_unregister_driver(&pld_snoc_ops);
+}
+
+/**
+ * pld_snoc_wlan_enable() - Enable WLAN
+ * @config: WLAN configuration data
+ * @mode: WLAN mode
+ * @host_version: host software version
+ *
+ * This function enables WLAN FW. It passed WLAN configuration data,
+ * WLAN mode and host software version to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version)
+{
+ struct icnss_wlan_enable_cfg cfg;
+ enum icnss_driver_mode icnss_mode;
+
+ cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
+ cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)
+ config->ce_tgt_cfg;
+ cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
+ cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
+ config->ce_svc_cfg;
+ cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
+ cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
+ config->shadow_reg_cfg;
+
+ switch (mode) {
+ case PLD_FTM:
+ icnss_mode = ICNSS_FTM;
+ break;
+ case PLD_EPPING:
+ icnss_mode = ICNSS_EPPING;
+ break;
+ default:
+ icnss_mode = ICNSS_MISSION;
+ break;
+ }
+ return icnss_wlan_enable(&cfg, icnss_mode, host_version);
+}
+
+/**
+ * pld_snoc_wlan_disable() - Disable WLAN
+ * @mode: WLAN mode
+ *
+ * This function disables WLAN FW. It passes WLAN mode to FW.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_snoc_wlan_disable(enum pld_driver_mode mode)
+{
+ return icnss_wlan_disable(ICNSS_OFF);
+}
+
+/**
+ * pld_snoc_get_soc_info() - Get SOC information
+ * @info: buffer to SOC information
+ *
+ * Return SOC info to the buffer.
+ *
+ * Return: 0 for success
+ * Non zero failure code for errors
+ */
+int pld_snoc_get_soc_info(struct pld_soc_info *info)
+{
+ int ret = 0;
+ struct icnss_soc_info icnss_info;
+
+ if (info == NULL)
+ return -ENODEV;
+
+ ret = icnss_get_soc_info(&icnss_info);
+ if (0 != ret)
+ return ret;
+
+ memcpy(info, &icnss_info, sizeof(*info));
+ return 0;
+}
+
+#endif
diff --git a/core/pld/src/pld_snoc.h b/core/pld/src/pld_snoc.h
new file mode 100644
index 0000000..3217106
--- /dev/null
+++ b/core/pld/src/pld_snoc.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+#ifndef __PLD_SNOC_H__
+#define __PLD_SNOC_H__
+
+#include "pld_common.h"
+
+#ifndef CONFIG_ICNSS
+static inline int pld_snoc_register_driver(void)
+{
+ return 0;
+}
+
+static inline void pld_snoc_unregister_driver(void)
+{
+ return;
+}
+static inline int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version)
+{
+ return 0;
+}
+static inline int pld_snoc_wlan_disable(enum pld_driver_mode mode)
+{
+ return 0;
+}
+static inline int icnss_ce_request_irq(unsigned int ce_id,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long flags, const char *name, void *ctx)
+{
+ return 0;
+}
+static inline int icnss_ce_free_irq(unsigned int ce_id, void *ctx)
+{
+ return 0;
+}
+static inline void icnss_enable_irq(unsigned int ce_id)
+{
+ return;
+}
+static inline void icnss_disable_irq(unsigned int ce_id)
+{
+ return;
+}
+static inline int icnss_get_soc_info(struct pld_soc_info *info)
+{
+ return 0;
+}
+static inline int icnss_get_ce_id(int irq)
+{
+ return 0;
+}
+static inline int pld_snoc_get_soc_info(struct pld_soc_info *info)
+{
+ return 0;
+}
+#else
+int pld_snoc_register_driver(void);
+void pld_snoc_unregister_driver(void);
+int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config,
+ enum pld_driver_mode mode, const char *host_version);
+int pld_snoc_wlan_disable(enum pld_driver_mode mode);
+int pld_snoc_get_soc_info(struct pld_soc_info *info);
+#endif
+
+#endif