| /* |
| * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. |
| * |
| * 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. |
| */ |
| |
| #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_PLD_SDIO_CNSS |
| #include <net/cnss.h> |
| #endif |
| #ifdef CONFIG_PLD_PCIE_CNSS |
| #include <net/cnss2.h> |
| #endif |
| #ifdef CONFIG_PLD_SNOC_ICNSS |
| #include <soc/qcom/icnss.h> |
| #endif |
| |
| #include "pld_pcie.h" |
| #include "pld_pcie_fw_sim.h" |
| #include "pld_snoc_fw_sim.h" |
| #include "pld_snoc.h" |
| #include "pld_sdio.h" |
| #include "pld_usb.h" |
| #include "qwlan_version.h" |
| |
| #define PLD_PCIE_REGISTERED BIT(0) |
| #define PLD_SNOC_REGISTERED BIT(1) |
| #define PLD_SDIO_REGISTERED BIT(2) |
| #define PLD_USB_REGISTERED BIT(3) |
| #define PLD_SNOC_FW_SIM_REGISTERED BIT(4) |
| #define PLD_PCIE_FW_SIM_REGISTERED BIT(5) |
| #define PLD_BUS_MASK 0xf |
| |
| 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_add_dev() - Add dev node to global context |
| * @pld_context: PLD global context |
| * @dev: device |
| * @ifdev: interface device |
| * @type: Bus type |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_add_dev(struct pld_context *pld_context, |
| struct device *dev, struct device *ifdev, |
| enum pld_bus_type type) |
| { |
| unsigned long flags; |
| struct dev_node *dev_node; |
| |
| dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL); |
| if (!dev_node) |
| return -ENOMEM; |
| |
| dev_node->dev = dev; |
| dev_node->ifdev = ifdev; |
| dev_node->bus_type = type; |
| |
| 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 0; |
| } |
| |
| /** |
| * pld_del_dev() - Delete dev node from global context |
| * @pld_context: PLD global context |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_del_dev(struct pld_context *pld_context, |
| struct device *dev) |
| { |
| unsigned long flags; |
| struct dev_node *dev_node, *tmp; |
| |
| 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); |
| } |
| |
| static struct dev_node *pld_get_dev_node(struct device *dev) |
| { |
| struct pld_context *pld_context; |
| struct dev_node *dev_node; |
| unsigned long flags; |
| |
| pld_context = pld_get_global_context(); |
| |
| if (!dev || !pld_context) { |
| pr_err("Invalid info: dev %pK, context %pK\n", |
| dev, pld_context); |
| return NULL; |
| } |
| |
| 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; |
| } |
| } |
| spin_unlock_irqrestore(&pld_context->pld_lock, flags); |
| |
| return NULL; |
| } |
| |
| /** |
| * 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 dev_node *dev_node = pld_get_dev_node(dev); |
| |
| if (dev_node) |
| return dev_node->bus_type; |
| else |
| return PLD_BUS_TYPE_NONE; |
| } |
| |
| /** |
| * pld_get_if_dev() - Bus interface/pipe dev of the device |
| * @dev: device |
| * |
| * Return: Bus sub-interface or pipe dev. |
| */ |
| static struct device *pld_get_if_dev(struct device *dev) |
| { |
| struct dev_node *dev_node = pld_get_dev_node(dev); |
| |
| if (dev_node) |
| return dev_node->ifdev; |
| else |
| return NULL; |
| } |
| |
| /** |
| * 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) { |
| 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; |
| pld_context->pld_driver_state = 0; |
| |
| ret = pld_pcie_register_driver(); |
| if (ret) { |
| pr_err("Fail to register pcie driver\n"); |
| goto fail_pcie; |
| } |
| pld_context->pld_driver_state |= PLD_PCIE_REGISTERED; |
| |
| ret = pld_snoc_register_driver(); |
| if (ret) { |
| pr_err("Fail to register snoc driver\n"); |
| goto fail_snoc; |
| } |
| pld_context->pld_driver_state |= PLD_SNOC_REGISTERED; |
| |
| ret = pld_sdio_register_driver(); |
| if (ret) { |
| pr_err("Fail to register sdio driver\n"); |
| goto fail_sdio; |
| } |
| pld_context->pld_driver_state |= PLD_SDIO_REGISTERED; |
| |
| ret = pld_snoc_fw_sim_register_driver(); |
| if (ret) { |
| pr_err("Fail to register snoc fw sim driver\n"); |
| goto fail_snoc_fw_sim; |
| } |
| pld_context->pld_driver_state |= PLD_SNOC_FW_SIM_REGISTERED; |
| |
| ret = pld_pcie_fw_sim_register_driver(); |
| if (ret) { |
| pr_err("Fail to register pcie fw sim driver\n"); |
| goto fail_pcie_fw_sim; |
| } |
| pld_context->pld_driver_state |= PLD_PCIE_FW_SIM_REGISTERED; |
| |
| ret = pld_usb_register_driver(); |
| if (ret) { |
| pr_err("Fail to register usb driver\n"); |
| goto fail_usb; |
| } |
| pld_context->pld_driver_state |= PLD_USB_REGISTERED; |
| |
| return ret; |
| |
| fail_usb: |
| pld_pcie_fw_sim_unregister_driver(); |
| fail_pcie_fw_sim: |
| pld_snoc_fw_sim_unregister_driver(); |
| fail_snoc_fw_sim: |
| pld_sdio_unregister_driver(); |
| fail_sdio: |
| pld_snoc_unregister_driver(); |
| fail_snoc: |
| pld_pcie_unregister_driver(); |
| fail_pcie: |
| pld_context->pld_driver_state = 0; |
| pld_context->ops = NULL; |
| 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) { |
| pr_err("global context is NULL\n"); |
| return; |
| } |
| |
| if (!pld_context->ops) { |
| pr_err("driver not registered\n"); |
| return; |
| } |
| |
| pld_pcie_unregister_driver(); |
| pld_snoc_fw_sim_unregister_driver(); |
| pld_pcie_fw_sim_unregister_driver(); |
| pld_snoc_unregister_driver(); |
| pld_sdio_unregister_driver(); |
| pld_usb_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 |
| * |
| * 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) |
| { |
| int ret = 0; |
| struct device *ifdev; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_wlan_enable(dev, config, mode, |
| QWLAN_VERSIONSTR); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_wlan_enable(dev, config, mode, |
| QWLAN_VERSIONSTR); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| ret = pld_sdio_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); |
| break; |
| case PLD_BUS_TYPE_USB: |
| ifdev = pld_get_if_dev(dev); |
| ret = pld_usb_wlan_enable(ifdev, config, mode, |
| QWLAN_VERSIONSTR); |
| 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(dev, mode); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_wlan_disable(dev, mode); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_wlan_disable(dev, mode); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_wlan_disable(dev, mode); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_set_fw_log_mode() - Set FW debug log mode |
| * @dev: device |
| * @fw_log_mode: 0 for No log, 1 for WMI, 2 for DIAG |
| * |
| * Switch Fw debug log mode between DIAG logging and WMI logging. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_set_fw_log_mode(dev, fw_log_mode); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_set_fw_log_mode(dev, fw_log_mode); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_default_fw_files() - Get default FW file names |
| * @pfw_files: buffer for FW file names |
| * |
| * Return default FW file names to the buffer. |
| * |
| * Return: void |
| */ |
| void pld_get_default_fw_files(struct pld_fw_files *pfw_files) |
| { |
| memset(pfw_files, 0, sizeof(*pfw_files)); |
| |
| strlcpy(pfw_files->image_file, PREFIX PLD_IMAGE_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->board_data, PREFIX PLD_BOARD_DATA_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->otp_data, PREFIX PLD_OTP_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->utf_file, PREFIX PLD_UTF_FIRMWARE_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->utf_board_data, PREFIX PLD_BOARD_DATA_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->epping_file, PREFIX PLD_EPPING_FILE, |
| PLD_MAX_FILE_NAME); |
| strlcpy(pfw_files->setup_file, PREFIX PLD_SETUP_FILE, |
| PLD_MAX_FILE_NAME); |
| } |
| |
| /** |
| * 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(dev, pfw_files, |
| target_type, |
| target_version); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| ret = pld_sdio_get_fw_files_for_target(pfw_files, |
| target_type, |
| target_version); |
| break; |
| case PLD_BUS_TYPE_USB: |
| ret = pld_usb_get_fw_files_for_target(pfw_files, |
| target_type, |
| target_version); |
| 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_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_link_down(dev); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_schedule_recovery_work() - Schedule recovery work |
| * @dev: device |
| * @reason: recovery reason |
| * |
| * Schedule a system self recovery work. |
| * |
| * Return: void |
| */ |
| void pld_schedule_recovery_work(struct device *dev, |
| enum pld_recovery_reason reason) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_schedule_recovery_work(dev, reason); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * 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 = pld_pcie_wlan_pm_control(dev, vote); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_pcie_get_virt_ramdump_mem(dev, size); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| mem = pld_sdio_get_virt_ramdump_mem(dev, size); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return mem; |
| } |
| |
| void pld_release_virt_ramdump_mem(struct device *dev, void *address) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_release_virt_ramdump_mem(address); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| pld_sdio_release_virt_ramdump_mem(address); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * 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: |
| pld_pcie_device_crashed(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| pld_sdio_device_crashed(dev); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_device_self_recovery() - Device self recovery |
| * @dev: device |
| * @reason: recovery reason |
| * |
| * Return: void |
| */ |
| void pld_device_self_recovery(struct device *dev, |
| enum pld_recovery_reason reason) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_device_self_recovery(dev, reason); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| pld_sdio_device_self_recovery(dev); |
| 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: |
| pld_pcie_intr_notify_q6(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| 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: |
| pld_pcie_request_pm_qos(dev, qos_val); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| /* To do Add call cns API */ |
| break; |
| case PLD_BUS_TYPE_USB: |
| 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: |
| pld_pcie_remove_pm_qos(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| /* To do Add call cns API */ |
| 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 = pld_pcie_request_bus_bandwidth(dev, bandwidth); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| /* To do Add call cns API */ |
| 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(dev, cap); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_get_platform_cap(dev, cap); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_pcie_get_sha_hash(dev, data, data_len, |
| hash_idx, out); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_pcie_get_fw_ptr(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_pcie_auto_suspend(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_pcie_auto_resume(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_force_wake_request() - Request vote to assert WAKE register |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_force_wake_request(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_force_wake_request(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_is_device_awake() - Check if it's ready to access MMIO registers |
| * @dev: device |
| * |
| * Return: True for device awake |
| * False for device not awake |
| * Negative failure code for errors |
| */ |
| int pld_is_device_awake(struct device *dev) |
| { |
| int ret = true; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_is_device_awake(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_force_wake_release() - Release vote to assert WAKE register |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_force_wake_release(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_force_wake_release(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| 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 = pld_snoc_ce_request_irq(dev, ce_id, |
| handler, flags, name, ctx); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_ce_request_irq(dev, ce_id, |
| handler, flags, name, ctx); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| 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 = pld_snoc_ce_free_irq(dev, ce_id, ctx); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_ce_free_irq(dev, ce_id, ctx); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| 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: |
| pld_snoc_enable_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pld_snoc_fw_sim_enable_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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: |
| pld_snoc_disable_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pld_snoc_fw_sim_disable_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_PCIE: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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(dev, info); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_get_soc_info(dev, info); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_get_soc_info(dev, info); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_soc_info(dev, info); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| 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 = pld_snoc_get_ce_id(dev, irq); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_get_ce_id(dev, irq); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_ce_id(dev, irq); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_irq() - Get IRQ number for given CE ID |
| * @dev: device |
| * @ce_id: CE ID |
| * |
| * Return: IRQ number |
| */ |
| int pld_get_irq(struct device *dev, int ce_id) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_get_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_get_irq(dev, ce_id); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_PCIE: |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_lock_pm_sem() - Lock PM semaphore |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_lock_pm_sem(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_lock_pm_sem(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_release_pm_sem() - Release PM semaphore |
| * @dev: device |
| * |
| * Return: void |
| */ |
| void pld_release_pm_sem(struct device *dev) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_release_pm_sem(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_power_on() - Power on WLAN hardware |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_power_on(struct device *dev) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| /* cnss platform driver handles PCIe SoC |
| * power on/off seqeunce so let CNSS driver |
| * handle the power on sequence for PCIe SoC |
| */ |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_power_on(dev); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_power_off() - Power off WLAN hardware |
| * @dev: device |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_power_off(struct device *dev) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| /* cnss platform driver handles PCIe SoC |
| * power on/off seqeunce so let CNSS driver |
| * handle the power off sequence for PCIe SoC |
| */ |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_power_off(dev); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_athdiag_read() - Read data from WLAN FW |
| * @dev: device |
| * @offset: address offset |
| * @memtype: memory type |
| * @datalen: data length |
| * @output: output buffer |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_athdiag_read(struct device *dev, uint32_t offset, |
| uint32_t memtype, uint32_t datalen, |
| uint8_t *output) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_athdiag_read(dev, offset, memtype, |
| datalen, output); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_athdiag_read(dev, offset, memtype, |
| datalen, output); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_athdiag_write() - Write data to WLAN FW |
| * @dev: device |
| * @offset: address offset |
| * @memtype: memory type |
| * @datalen: data length |
| * @input: input buffer |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_athdiag_write(struct device *dev, uint32_t offset, |
| uint32_t memtype, uint32_t datalen, |
| uint8_t *input) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_athdiag_write(dev, offset, memtype, |
| datalen, input); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_athdiag_write(dev, offset, memtype, |
| datalen, input); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_smmu_get_domain() - Get SMMU domain |
| * @dev: device |
| * |
| * Return: Pointer to the domain |
| */ |
| #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) |
| void *pld_smmu_get_domain(struct device *dev) |
| { |
| void *ptr = NULL; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ptr = pld_snoc_smmu_get_domain(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ptr = pld_pcie_smmu_get_domain(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| pr_err("Not supported on type %d\n", type); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| |
| return ptr; |
| } |
| #else |
| /** |
| * pld_smmu_get_mapping() - Get SMMU mapping context |
| * @dev: device |
| * |
| * Return: Pointer to the mapping context |
| */ |
| void *pld_smmu_get_mapping(struct device *dev) |
| { |
| void *ptr = NULL; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ptr = pld_snoc_smmu_get_mapping(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ptr = pld_pcie_smmu_get_mapping(dev); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| |
| return ptr; |
| } |
| #endif |
| |
| /** |
| * pld_smmu_map() - Map SMMU |
| * @dev: device |
| * @paddr: physical address that needs to map to |
| * @iova_addr: IOVA address |
| * @size: size to be mapped |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_smmu_map(struct device *dev, phys_addr_t paddr, |
| uint32_t *iova_addr, size_t size) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_smmu_map(dev, paddr, iova_addr, size); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_smmu_map(dev, paddr, iova_addr, size); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_user_msi_assignment() - Get MSI assignment information |
| * @dev: device structure |
| * @user_name: name of the user who requests the MSI assignment |
| * @num_vectors: number of the MSI vectors assigned for the user |
| * @user_base_data: MSI base data assigned for the user, this equals to |
| * endpoint base data from config space plus base vector |
| * @base_vector: base MSI vector (offset) number assigned for the user |
| * |
| * Return: 0 for success |
| * Negative failure code for errors |
| */ |
| int pld_get_user_msi_assignment(struct device *dev, char *user_name, |
| int *num_vectors, uint32_t *user_base_data, |
| uint32_t *base_vector) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_user_msi_assignment(dev, user_name, |
| num_vectors, |
| user_base_data, |
| base_vector); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_get_user_msi_assignment(dev, user_name, |
| num_vectors, |
| user_base_data, |
| base_vector); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pr_err("Not supported on type %d\n", type); |
| ret = -ENODEV; |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_srng_request_irq() - Register IRQ for SRNG |
| * @dev: device |
| * @irq: IRQ 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_srng_request_irq(struct device *dev, int irq, irq_handler_t handler, |
| unsigned long irqflags, |
| const char *devname, |
| void *dev_data) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = request_irq(irq, handler, irqflags, devname, dev_data); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_request_irq(dev, irq, handler, |
| irqflags, devname, |
| dev_data); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pr_err("Not supported on type %d\n", type); |
| ret = -ENODEV; |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_srng_free_irq() - Free IRQ for SRNG |
| * @dev: device |
| * @irq: IRQ 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_srng_free_irq(struct device *dev, int irq, void *dev_data) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| free_irq(irq, dev_data); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_free_irq(dev, irq, dev_data); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pr_err("Not supported on type %d\n", type); |
| ret = -ENODEV; |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_srng_enable_irq() - Enable IRQ for SRNG |
| * @dev: device |
| * @irq: IRQ number |
| * |
| * Return: void |
| */ |
| void pld_srng_enable_irq(struct device *dev, int irq) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| pld_pcie_fw_sim_enable_irq(dev, irq); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| enable_irq(irq); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_disable_irq() - Disable IRQ for SRNG |
| * @dev: device |
| * @irq: IRQ number |
| * |
| * Return: void |
| */ |
| void pld_srng_disable_irq(struct device *dev, int irq) |
| { |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| pld_pcie_fw_sim_disable_irq(dev, irq); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| disable_irq_nosync(irq); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| } |
| |
| /** |
| * pld_pci_read_config_word() - Read PCI config |
| * @pdev: pci device |
| * @offset: Config space offset |
| * @val : Value |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_pci_read_config_word(struct pci_dev *pdev, int offset, uint16_t *val) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(&pdev->dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pci_read_config_word(pdev, offset, val); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_pci_write_config_word() - Write PCI config |
| * @pdev: pci device |
| * @offset: Config space offset |
| * @val : Value |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_pci_write_config_word(struct pci_dev *pdev, int offset, uint16_t val) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(&pdev->dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pci_write_config_word(pdev, offset, val); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_pci_read_config_dword() - Read PCI config |
| * @pdev: pci device |
| * @offset: Config space offset |
| * @val : Value |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_pci_read_config_dword(struct pci_dev *pdev, int offset, uint32_t *val) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(&pdev->dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pci_read_config_dword(pdev, offset, val); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_pci_write_config_dword() - Write PCI config |
| * @pdev: pci device |
| * @offset: Config space offset |
| * @val : Value |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_pci_write_config_dword(struct pci_dev *pdev, int offset, uint32_t val) |
| { |
| int ret = 0; |
| |
| switch (pld_get_bus_type(&pdev->dev)) { |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pci_write_config_dword(pdev, offset, val); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_msi_irq() - Get MSI IRQ number used for request_irq() |
| * @dev: device structure |
| * @vector: MSI vector (offset) number |
| * |
| * Return: Positive IRQ number for success |
| * Negative failure code for errors |
| */ |
| int pld_get_msi_irq(struct device *dev, unsigned int vector) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_get_msi_irq(dev, vector); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = pld_pcie_fw_sim_get_msi_irq(dev, vector); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pr_err("Not supported on type %d\n", type); |
| ret = -ENODEV; |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_get_msi_address() - Get the MSI address |
| * @dev: device structure |
| * @msi_addr_low: lower 32-bit of the address |
| * @msi_addr_high: higher 32-bit of the address |
| * |
| * Return: Void |
| */ |
| void pld_get_msi_address(struct device *dev, uint32_t *msi_addr_low, |
| uint32_t *msi_addr_high) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| pld_pcie_get_msi_address(dev, msi_addr_low, msi_addr_high); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| pld_pcie_fw_sim_get_msi_address(dev, msi_addr_low, |
| msi_addr_high); |
| break; |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| pr_err("Not supported on type %d\n", type); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| } |
| |
| /** |
| * pld_is_drv_connected() - Check if DRV subsystem is connected |
| * @dev: device structure |
| * |
| * Return: 1 DRV is connected |
| * 0 DRV is not connected |
| * Non zero failure code for errors |
| */ |
| int pld_is_drv_connected(struct device *dev) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| int ret = 0; |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_is_drv_connected(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_socinfo_get_serial_number() - Get SOC serial number |
| * @dev: device |
| * |
| * Return: SOC serial number |
| */ |
| unsigned int pld_socinfo_get_serial_number(struct device *dev) |
| { |
| unsigned int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_socinfo_get_serial_number(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_PCIE: |
| pr_err("Not supported on type %d\n", type); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_is_qmi_disable() - Check QMI support is present or not |
| * @dev: device |
| * |
| * Return: 1 QMI is not supported |
| * 0 QMI is supported |
| * Non zero failure code for errors |
| */ |
| int pld_is_qmi_disable(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_is_qmi_disable(dev); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_PCIE: |
| case PLD_BUS_TYPE_SDIO: |
| pr_err("Not supported on type %d\n", type); |
| ret = -EINVAL; |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_is_fw_down() - Check WLAN fw is down or not |
| * |
| * @dev: device |
| * |
| * This API will be called to check if WLAN FW is down or not. |
| * |
| * Return: 0 FW is not down |
| * Otherwise FW is down |
| * Always return 0 for unsupported bus type |
| */ |
| int pld_is_fw_down(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| struct device *ifdev; |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_is_fw_down(dev); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| ret = pld_snoc_fw_sim_is_fw_down(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_is_fw_down(dev); |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| break; |
| case PLD_BUS_TYPE_USB: |
| ifdev = pld_get_if_dev(dev); |
| ret = pld_usb_is_fw_down(ifdev); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * pld_force_assert_target() - Send a force assert to FW. |
| * This can use various sideband requests available at platform to |
| * initiate a FW assert. |
| * @dev: device |
| * |
| * Return: 0 if force assert of target was triggered successfully |
| * Non zero failure code for errors |
| */ |
| int pld_force_assert_target(struct device *dev) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| return pld_snoc_force_assert_target(dev); |
| case PLD_BUS_TYPE_PCIE: |
| return pld_pcie_force_assert_target(dev); |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| return -EOPNOTSUPP; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SDIO: |
| return -EINVAL; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| return -EINVAL; |
| } |
| } |
| |
| /** |
| * pld_collect_rddm() - Collect ramdump before FW assert. |
| * This can used to collect ramdump before FW assert. |
| * @dev: device |
| * |
| * Return: 0 if ramdump is collected successfully |
| * Non zero failure code for errors |
| */ |
| int pld_collect_rddm(struct device *dev) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| return pld_pcie_collect_rddm(dev); |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| return 0; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| return -EINVAL; |
| } |
| } |
| |
| /** |
| * pld_qmi_send_get() - Indicate certain data to be sent over QMI |
| * @dev: device pointer |
| * |
| * This API can be used to indicate certain data to be sent over QMI. |
| * pld_qmi_send() is expected to be called later. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_qmi_send_get(struct device *dev) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| return pld_pcie_qmi_send_get(dev); |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| return 0; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| return -EINVAL; |
| } |
| } |
| |
| /** |
| * pld_qmi_send_put() - Indicate response sent over QMI has been processed |
| * @dev: device pointer |
| * |
| * This API can be used to indicate response of the data sent over QMI has |
| * been processed. |
| * |
| * Return: 0 for success |
| * Non zero failure code for errors |
| */ |
| int pld_qmi_send_put(struct device *dev) |
| { |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_PCIE: |
| return pld_pcie_qmi_send_put(dev); |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| return 0; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| return -EINVAL; |
| } |
| } |
| |
| /** |
| * pld_qmi_send() - Send data request over QMI |
| * @dev: device pointer |
| * @type: type of the send data operation |
| * @cmd: buffer pointer of send data request command |
| * @cmd_len: size of the command buffer |
| * @cb_ctx: context pointer if any to pass back in callback |
| * @cb: callback pointer to pass response back |
| * |
| * This API can be used to send data request over QMI. |
| * |
| * Return: 0 if data request sends successfully |
| * Non zero failure code for errors |
| */ |
| int pld_qmi_send(struct device *dev, int type, void *cmd, |
| int cmd_len, void *cb_ctx, |
| int (*cb)(void *ctx, void *event, int event_len)) |
| { |
| enum pld_bus_type bus_type = pld_get_bus_type(dev); |
| |
| switch (bus_type) { |
| case PLD_BUS_TYPE_PCIE: |
| return pld_pcie_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); |
| case PLD_BUS_TYPE_SNOC: |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| return -EINVAL; |
| default: |
| pr_err("Invalid device type %d\n", bus_type); |
| return -EINVAL; |
| } |
| } |
| |
| /** |
| * pld_is_fw_dump_skipped() - get fw dump skipped status. |
| * The subsys ssr status help the driver to decide whether to skip |
| * the FW memory dump when FW assert. |
| * For SDIO case, the memory dump progress takes 1 minutes to |
| * complete, which is not acceptable in SSR enabled. |
| * |
| * Return: true if need to skip FW dump. |
| */ |
| bool pld_is_fw_dump_skipped(struct device *dev) |
| { |
| bool ret = false; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SDIO: |
| ret = pld_sdio_is_fw_dump_skipped(); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| default: |
| break; |
| } |
| return ret; |
| } |
| |
| int pld_is_pdr(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_is_pdr(); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| default: |
| break; |
| } |
| return ret; |
| } |
| |
| int pld_is_fw_rejuvenate(struct device *dev) |
| { |
| int ret = 0; |
| enum pld_bus_type type = pld_get_bus_type(dev); |
| |
| switch (type) { |
| case PLD_BUS_TYPE_SNOC: |
| ret = pld_snoc_is_fw_rejuvenate(); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| default: |
| break; |
| } |
| return ret; |
| } |
| |
| bool pld_have_platform_driver_support(struct device *dev) |
| { |
| bool ret = false; |
| |
| switch (pld_get_bus_type(dev)) { |
| case PLD_BUS_TYPE_PCIE: |
| ret = pld_pcie_platform_driver_support(); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| ret = true; |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| case PLD_BUS_TYPE_SNOC: |
| break; |
| case PLD_BUS_TYPE_SDIO: |
| ret = pld_sdio_platform_driver_support(); |
| break; |
| default: |
| pr_err("Invalid device type\n"); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| int pld_idle_shutdown(struct device *dev, |
| int (*shutdown_cb)(struct device *dev)) |
| { |
| int errno = -EINVAL; |
| enum pld_bus_type type; |
| |
| if (!shutdown_cb) |
| return -EINVAL; |
| |
| type = pld_get_bus_type(dev); |
| switch (type) { |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC: |
| errno = shutdown_cb(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| errno = pld_pcie_idle_shutdown(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| errno = pld_pcie_fw_sim_idle_shutdown(dev); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| errno = pld_snoc_fw_sim_idle_shutdown(dev); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| |
| return errno; |
| } |
| |
| int pld_idle_restart(struct device *dev, |
| int (*restart_cb)(struct device *dev)) |
| { |
| int errno = -EINVAL; |
| enum pld_bus_type type; |
| |
| if (!restart_cb) |
| return -EINVAL; |
| |
| type = pld_get_bus_type(dev); |
| switch (type) { |
| case PLD_BUS_TYPE_SDIO: |
| case PLD_BUS_TYPE_USB: |
| case PLD_BUS_TYPE_SNOC: |
| errno = restart_cb(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE: |
| errno = pld_pcie_idle_restart(dev); |
| break; |
| case PLD_BUS_TYPE_PCIE_FW_SIM: |
| errno = pld_pcie_fw_sim_idle_restart(dev); |
| break; |
| case PLD_BUS_TYPE_SNOC_FW_SIM: |
| errno = pld_snoc_fw_sim_idle_restart(dev); |
| break; |
| default: |
| pr_err("Invalid device type %d\n", type); |
| break; |
| } |
| |
| return errno; |
| } |