449 lines
9.6 KiB
C
449 lines
9.6 KiB
C
|
|
/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||
|
|
*
|
||
|
|
* This program is free software; you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
|
* only version 2 as published by the Free Software Foundation.
|
||
|
|
*
|
||
|
|
* This program is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
* GNU General Public License for more details.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "bus.h"
|
||
|
|
#include "debug.h"
|
||
|
|
#include "pci.h"
|
||
|
|
#include "usb.h"
|
||
|
|
|
||
|
|
enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
|
||
|
|
{
|
||
|
|
if (!dev)
|
||
|
|
return CNSS_BUS_NONE;
|
||
|
|
|
||
|
|
if (!dev->bus)
|
||
|
|
return CNSS_BUS_NONE;
|
||
|
|
|
||
|
|
if (memcmp(dev->bus->name, "pci", 3) == 0)
|
||
|
|
return CNSS_BUS_PCI;
|
||
|
|
else
|
||
|
|
return CNSS_BUS_NONE;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum cnss_dev_bus_type cnss_get_bus_type(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
int ret;
|
||
|
|
struct device *dev;
|
||
|
|
u32 bus_type = CNSS_BUS_NONE;
|
||
|
|
|
||
|
|
if (plat_priv->is_converged_dt) {
|
||
|
|
dev = &plat_priv->plat_dev->dev;
|
||
|
|
ret = of_property_read_u32(dev->of_node, "qcom,bus-type",
|
||
|
|
&bus_type);
|
||
|
|
if (!ret)
|
||
|
|
cnss_pr_dbg("Got bus type[%u] from dt\n", bus_type);
|
||
|
|
else
|
||
|
|
cnss_pr_err("No bus type for converged dt\n");
|
||
|
|
|
||
|
|
return bus_type;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Get bus type according to device id if it's not converged DT */
|
||
|
|
switch (plat_priv->device_id) {
|
||
|
|
case QCA6174_DEVICE_ID:
|
||
|
|
case QCA6290_DEVICE_ID:
|
||
|
|
case QCA6390_DEVICE_ID:
|
||
|
|
case QCN7605_DEVICE_ID:
|
||
|
|
bus_type = CNSS_BUS_PCI;
|
||
|
|
break;
|
||
|
|
case QCN7605_COMPOSITE_DEVICE_ID:
|
||
|
|
case QCN7605_STANDALONE_DEVICE_ID:
|
||
|
|
bus_type = CNSS_BUS_USB;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unknown device: 0x%lx\n", plat_priv->device_id);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return bus_type;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (cnss_get_bus_type(plat_priv) == CNSS_BUS_USB)
|
||
|
|
return false;
|
||
|
|
else
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void *cnss_bus_dev_to_bus_priv(struct device *dev)
|
||
|
|
{
|
||
|
|
if (!dev)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
switch (cnss_get_dev_bus_type(dev)) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_get_pci_priv(to_pci_dev(dev));
|
||
|
|
default:
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
|
||
|
|
{
|
||
|
|
void *bus_priv;
|
||
|
|
|
||
|
|
if (!dev)
|
||
|
|
return cnss_get_plat_priv(NULL);
|
||
|
|
|
||
|
|
bus_priv = cnss_bus_dev_to_bus_priv(dev);
|
||
|
|
if (!bus_priv)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
switch (cnss_get_dev_bus_type(dev)) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_priv_to_plat_priv(bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_priv_to_plat_priv(bus_priv);
|
||
|
|
default:
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_init(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_init(plat_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_init(plat_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void cnss_bus_deinit(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
cnss_pci_deinit(plat_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
cnss_usb_deinit(plat_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_load_m3(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_load_m3(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_alloc_fw_mem(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_alloc_qdss_mem(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_alloc_qdss_mem(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void cnss_bus_free_qdss_mem(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
cnss_pci_free_qdss_mem(plat_priv->bus_priv);
|
||
|
|
return;
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
u32 cnss_bus_get_wake_irq(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_get_wake_msi(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_force_fw_assert_hdlr(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void cnss_bus_fw_boot_timeout_hdlr(unsigned long data)
|
||
|
|
{
|
||
|
|
struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data;
|
||
|
|
|
||
|
|
if (!plat_priv)
|
||
|
|
return;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void cnss_bus_collect_dump_info(struct cnss_plat_data *plat_priv, bool in_panic)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_collect_dump_info(plat_priv->bus_priv,
|
||
|
|
in_panic);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_call_driver_probe(plat_priv->bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_call_driver_probe(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_call_driver_remove(plat_priv->bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_call_driver_remove(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_dev_powerup(plat_priv->bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return 0;
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_dev_shutdown(plat_priv->bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return 0;
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_dev_crash_shutdown(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_dev_crash_shutdown(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_dev_ramdump(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_dev_ramdump(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_register_driver_hdlr(plat_priv->bus_priv, data);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv);
|
||
|
|
case CNSS_BUS_USB:
|
||
|
|
return cnss_usb_unregister_driver_hdlr(plat_priv->bus_priv);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
|
||
|
|
int modem_current_status)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_call_driver_modem_status(plat_priv->bus_priv,
|
||
|
|
modem_current_status);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
|
||
|
|
enum cnss_driver_status status)
|
||
|
|
{
|
||
|
|
if (!plat_priv)
|
||
|
|
return -ENODEV;
|
||
|
|
|
||
|
|
switch (plat_priv->bus_type) {
|
||
|
|
case CNSS_BUS_PCI:
|
||
|
|
return cnss_pci_update_status(plat_priv->bus_priv, status);
|
||
|
|
default:
|
||
|
|
cnss_pr_err("Unsupported bus type: %d\n",
|
||
|
|
plat_priv->bus_type);
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int cnss_get_msi_assignment(struct cnss_plat_data *plat_priv,
|
||
|
|
char *msi_name,
|
||
|
|
int *num_vectors, u32 *user_base_data,
|
||
|
|
u32 *base_vector)
|
||
|
|
{
|
||
|
|
struct cnss_pci_data *pci_priv;
|
||
|
|
|
||
|
|
pci_priv = plat_priv->bus_priv;
|
||
|
|
return cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
|
||
|
|
msi_name,
|
||
|
|
num_vectors,
|
||
|
|
user_base_data,
|
||
|
|
base_vector);
|
||
|
|
}
|