blob: f4a762edcaa26f8d52d21387d012f99a667340c3 [file] [log] [blame]
/*
* Copyright (c) 2020, 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 <linux/err.h>
#include <linux/remoteproc.h>
#include <linux/remoteproc/qcom_rproc.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-direction.h>
#include <linux/mhi.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/msi.h>
#include <linux/irq.h>
#define MHI_MAX_DEVICE 2
/* MHI MMIO register mapping */
#define PCI_INVALID_READ(val) (val == U32_MAX)
/* PCI specific macros */
#define PCI_BAR_NUM 0
#define PCI_DMA_MASK_64_BIT 64
#define MHI_TIMEOUT_DEFAULT 10000
#define PCIE_SOC_GLOBAL_RESET_V 1
#define PCIE_SOC_GLOBAL_RESET_ADDRESS 0x3008
#define PCIE_TXVECDB 0x360
#define PCIE_TXVECSTATUS 0x368
#define PCIE_RXVECDB 0x394
#define PCIE_RXVECSTATUS 0x39C
#define MHISTATUS 0x48
#define MHICTRL 0x38
#define MHICTRL_RESET_MASK 0x2
/* Add DEBUG related here */
enum MHITEST_DEBUG_KLVL{
MHITEST_LOG_LVL_VERBOSE,
MHITEST_LOG_LVL_INFO,
MHITEST_LOG_LVL_ERR,
};
extern int debug_lvl;
#define pr_mhitest(msg, ...) pr_err("[mhitest]: " msg, ##__VA_ARGS__)
#define pr_mhitest2(msg, ...) \
pr_err("[mhitest]: %s[%d] " msg, __func__, __LINE__, ##__VA_ARGS__)
#define MHITEST_EMERG(msg, ...) do {\
pr_err("[mhitest][A]: [%s] " msg, __func__, ##__VA_ARGS__);\
} while (0)
#define MHITEST_ERR(msg, ...) do {\
if (debug_lvl <= MHITEST_LOG_LVL_ERR) \
pr_err("[mhitest][E]: [%s] " msg, __func__, ##__VA_ARGS__);\
} while (0)
#define MHITEST_VERB(msg, ...) do {\
if (debug_lvl <= MHITEST_LOG_LVL_VERBOSE) \
pr_err("[mhitest][D]: [%s][%d] " msg, __func__, __LINE__, ##__VA_ARGS__);\
} while (0)
#define MHITEST_LOG(msg, ...) do {\
if (debug_lvl <= MHITEST_LOG_LVL_INFO) \
pr_err("[mhitest][I]: [%s] " msg, __func__, ##__VA_ARGS__);\
} while (0)
#define VERIFY_ME(val, announce)\
do { \
if (val) { \
pr_mhitest2("%s Error val :%d\n", announce, val);\
} \
else { \
pr_mhitest2("%s Pass!\n", announce); \
} \
} while (0)
#define QTI_PCI_VENDOR_ID 0x17CB
#define QCN90xx_DEVICE_ID 0x1104
#define QCN92XX_DEVICE_ID 0x1109
#define PCI_LINK_DOWN 0
/*
*Structure specific to mhitest module
*/
struct mhitest_msi_user {
char *name;
int num_vectors;
u32 base_vector;
};
enum fw_dump_type {
FW_IMAGE,
FW_RDDM,
FW_REMOTE_HEAP,
};
/* recovery reasons using only default and rddm one for now */
enum mhitest_recovery_reason {
MHI_DEFAULT,
MHI_LINK_DOWN,
MHI_RDDM,
MHI_TIMEOUT,
};
struct mhitest_msi_config {
int total_vectors;
int total_users;
struct mhitest_msi_user *users;
};
struct mhitest_dump_seg {
unsigned long address;
void *v_address;
unsigned long size;
u32 type;
};
struct mhitest_dump_data {
u32 version;
u32 magic;
char name[32];
phys_addr_t paddr;
int nentries;
u32 seg_version;
};
struct mhitest_ramdump_info {
struct ramdump_device *ramdump_dev;
unsigned long ramdump_size;
void *dump_data_vaddr;
u8 dump_data_valid;
struct mhitest_dump_data dump_data;
};
struct mhitest_platform {
struct platform_device *plat_dev;
struct pci_dev *pci_dev;
unsigned long device_id;
const struct pci_device_id *pci_dev_id;
u16 def_link_speed;
u16 def_link_width;
u8 pci_link_state;
struct pci_saved_state *pci_dev_default_state;
void __iomem *bar;
char fw_name[30];
/*mhi msi */
struct mhitest_msi_config *msi_config;
u32 msi_ep_base_data;
struct mhi_controller *mhi_ctrl;
/* subsystem related */
char *mhitest_ss_desc_name;
phandle rproc_handle;
struct rproc *subsys_handle;
/* ramdump */
struct mhitest_ramdump_info mhitest_rdinfo;
/* event work queue*/
struct list_head event_list;
spinlock_t event_lock; /* spinlock for driver work event handling */
struct work_struct event_work;
struct workqueue_struct *event_wq;
/* probed device no. 0 to (MAX-1)*/
int d_instance;
/* klog level for mhitest driver */
enum MHITEST_DEBUG_KLVL mhitest_klog_lvl;
};
enum MHI_STATE {
MHI_INIT,
MHI_DEINIT,
MHI_POWER_ON,
MHI_POWER_OFF,
MHI_FORCE_POWER_OFF,
};
enum mhitest_event_type {
MHITEST_RECOVERY_EVENT,
MHITEST_MAX_EVENT,
};
struct mhitest_recovery_data {
enum mhitest_recovery_reason reason;
};
struct mhitest_driver_event {
struct list_head list;
enum mhitest_event_type type;
bool sync;
struct completion complete;
int ret;
void *data;
};
int mhitest_pci_register(void);
int mhitest_subsystem_register(struct mhitest_platform *);
void mhitest_pci_unregister(void);
void mhitest_subsystem_unregister(struct mhitest_platform *);
int mhitest_pci_enable_bus(struct mhitest_platform *);
struct mhitest_platform *get_mhitest_mplat(int);
struct mhitest_platform *get_mhitest_mplat_by_pcidev(struct pci_dev *pci_dev);
int mhitest_pci_en_msi(struct mhitest_platform *);
int mhitest_pci_register_mhi(struct mhitest_platform *);
int mhitest_pci_get_mhi_msi(struct mhitest_platform *);
int mhitest_pci_get_link_status(struct mhitest_platform *);
int mhitest_prepare_pci_mhi_msi(struct mhitest_platform *);
int mhitest_prepare_start_mhi(struct mhitest_platform *);
int mhitest_dump_info(struct mhitest_platform *mplat, bool in_panic);
int mhitest_post_event(struct mhitest_platform *,
struct mhitest_recovery_data *, enum mhitest_event_type, u32 flags);
struct platform_device *get_plat_device(void);
int mhitest_store_mplat(struct mhitest_platform *);
void mhitest_free_mplat(struct mhitest_platform *);
int mhitest_event_work_init(struct mhitest_platform *);
void mhitest_event_work_deinit(struct mhitest_platform *);
int mhitest_pci_start_mhi(struct mhitest_platform *);
void mhitest_global_soc_reset(struct mhitest_platform *);
int mhitest_ss_powerup(struct rproc *);
int mhitest_pci_set_mhi_state(struct mhitest_platform *, enum MHI_STATE);
void mhitest_pci_disable_bus(struct mhitest_platform *);
int mhitest_unregister_ramdump(struct mhitest_platform *);
int mhitest_pci_remove_all(struct mhitest_platform *);