354 lines
9.6 KiB
C
354 lines
9.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#ifndef _MHI_CORE_MISC_H_
|
|
#define _MHI_CORE_MISC_H_
|
|
|
|
#include <linux/mhi_misc.h>
|
|
#include <linux/msm_pcie.h>
|
|
|
|
#define MHI_FORCE_WAKE_DELAY_US (100)
|
|
#define MHI_IPC_LOG_PAGES (100)
|
|
#define MAX_RDDM_TABLE_SIZE (8)
|
|
#define MHI_REG_SIZE (SZ_4K)
|
|
|
|
#define REG_WRITE_QUEUE_LEN 512
|
|
|
|
/* MHI misc capability registers */
|
|
#define MISC_OFFSET (0x24)
|
|
#define MISC_CAP_MASK (0xFFFFFFFF)
|
|
#define MISC_CAP_SHIFT (0)
|
|
|
|
#define CAP_CAPID_MASK (0xFF000000)
|
|
#define CAP_CAPID_SHIFT (24)
|
|
#define CAP_NEXT_CAP_MASK (0x00FFF000)
|
|
#define CAP_NEXT_CAP_SHIFT (12)
|
|
|
|
/* MHI Bandwidth scaling offsets */
|
|
#define BW_SCALE_CFG_OFFSET (0x04)
|
|
#define BW_SCALE_CFG_CHAN_DB_ID_MASK (0xFE000000)
|
|
#define BW_SCALE_CFG_CHAN_DB_ID_SHIFT (25)
|
|
#define BW_SCALE_CFG_ENABLED_MASK (0x01000000)
|
|
#define BW_SCALE_CFG_ENABLED_SHIFT (24)
|
|
#define BW_SCALE_CFG_ER_ID_MASK (0x00F80000)
|
|
#define BW_SCALE_CFG_ER_ID_SHIFT (19)
|
|
|
|
#define BW_SCALE_CAP_ID (3)
|
|
#define MHI_TRE_GET_EV_BW_REQ_SEQ(tre) (((tre)->dword[0] >> 8) & 0xFF)
|
|
#define MHI_BW_SCALE_CHAN_DB 126
|
|
|
|
#define MHI_BW_SCALE_SETUP(er_index) (((MHI_BW_SCALE_CHAN_DB << \
|
|
BW_SCALE_CFG_CHAN_DB_ID_SHIFT) & BW_SCALE_CFG_CHAN_DB_ID_MASK) | \
|
|
((1 << BW_SCALE_CFG_ENABLED_SHIFT) & BW_SCALE_CFG_ENABLED_MASK) | \
|
|
(((er_index) << BW_SCALE_CFG_ER_ID_SHIFT) & BW_SCALE_CFG_ER_ID_MASK))
|
|
|
|
#define MHI_BW_SCALE_RESULT(status, seq) (((status) & 0xF) << 8 | \
|
|
((seq) & 0xFF))
|
|
#define MHI_BW_SCALE_NACK 0xF
|
|
|
|
/* subsystem failure reason cfg command */
|
|
#define MHI_TRE_CMD_SFR_CFG_PTR(ptr) (ptr)
|
|
#define MHI_TRE_CMD_SFR_CFG_DWORD0(len) (len)
|
|
#define MHI_TRE_CMD_SFR_CFG_DWORD1 (MHI_CMD_SFR_CFG << 16)
|
|
|
|
/* MHI Timesync offsets */
|
|
#define TIMESYNC_CFG_OFFSET (0x04)
|
|
#define TIMESYNC_CFG_ENABLED_MASK (0x80000000)
|
|
#define TIMESYNC_CFG_ENABLED_SHIFT (31)
|
|
#define TIMESYNC_CFG_CHAN_DB_ID_MASK (0x0000FF00)
|
|
#define TIMESYNC_CFG_CHAN_DB_ID_SHIFT (8)
|
|
#define TIMESYNC_CFG_ER_ID_MASK (0x000000FF)
|
|
#define TIMESYNC_CFG_ER_ID_SHIFT (0)
|
|
|
|
#define TIMESYNC_TIME_LOW_OFFSET (0x8)
|
|
#define TIMESYNC_TIME_HIGH_OFFSET (0xC)
|
|
|
|
#define MHI_TIMESYNC_CHAN_DB (125)
|
|
#define TIMESYNC_CAP_ID (2)
|
|
|
|
#define MHI_TIMESYNC_DB_SETUP(er_index) ((MHI_TIMESYNC_CHAN_DB << \
|
|
TIMESYNC_CFG_CHAN_DB_ID_SHIFT) & TIMESYNC_CFG_CHAN_DB_ID_MASK | \
|
|
(1 << TIMESYNC_CFG_ENABLED_SHIFT) & TIMESYNC_CFG_ENABLED_MASK | \
|
|
((er_index) << TIMESYNC_CFG_ER_ID_SHIFT) & TIMESYNC_CFG_ER_ID_MASK)
|
|
|
|
#define MHI_VERB(dev, fmt, ...) do { \
|
|
struct mhi_private *mhi_priv = \
|
|
dev_get_drvdata(&mhi_cntrl->mhi_dev->dev); \
|
|
dev_dbg(dev, "[D][%s] " fmt, __func__, ##__VA_ARGS__); \
|
|
if (mhi_priv && mhi_priv->log_lvl <= MHI_MSG_LVL_VERBOSE) \
|
|
ipc_log_string(mhi_priv->log_buf, "[D][%s] " fmt, __func__, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define MHI_LOG(dev, fmt, ...) do { \
|
|
struct mhi_private *mhi_priv = \
|
|
dev_get_drvdata(&mhi_cntrl->mhi_dev->dev); \
|
|
dev_dbg(dev, "[I][%s] " fmt, __func__, ##__VA_ARGS__); \
|
|
if (mhi_priv && mhi_priv->log_lvl <= MHI_MSG_LVL_INFO) \
|
|
ipc_log_string(mhi_priv->log_buf, "[I][%s] " fmt, __func__, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define MHI_ERR(dev, fmt, ...) do { \
|
|
struct mhi_private *mhi_priv = \
|
|
dev_get_drvdata(&mhi_cntrl->mhi_dev->dev); \
|
|
dev_err(dev, "[E][%s] " fmt, __func__, ##__VA_ARGS__); \
|
|
if (mhi_priv && mhi_priv->log_lvl <= MHI_MSG_LVL_ERROR) \
|
|
ipc_log_string(mhi_priv->log_buf, "[E][%s] " fmt, __func__, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define MHI_CRITICAL(dev, fmt, ...) do { \
|
|
struct mhi_private *mhi_priv = \
|
|
dev_get_drvdata(&mhi_cntrl->mhi_dev->dev); \
|
|
dev_crit(dev, "[C][%s] " fmt, __func__, ##__VA_ARGS__); \
|
|
if (mhi_priv && mhi_priv->log_lvl <= MHI_MSG_LVL_CRITICAL) \
|
|
ipc_log_string(mhi_priv->log_buf, "[C][%s] " fmt, __func__, \
|
|
##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
/**
|
|
* struct rddm_table_info - rddm table info
|
|
* @base_address - Start offset of the file
|
|
* @actual_phys_address - phys addr offset of file
|
|
* @size - size of file
|
|
* @description - file description
|
|
* @file_name - name of file
|
|
*/
|
|
struct rddm_table_info {
|
|
u64 base_address;
|
|
u64 actual_phys_address;
|
|
u64 size;
|
|
char description[20];
|
|
char file_name[20];
|
|
};
|
|
|
|
/**
|
|
* struct rddm_header - rddm header
|
|
* @version - header ver
|
|
* @header_size - size of header
|
|
* @rddm_table_info - array of rddm table info
|
|
*/
|
|
struct rddm_header {
|
|
u32 version;
|
|
u32 header_size;
|
|
struct rddm_table_info table_info[MAX_RDDM_TABLE_SIZE];
|
|
};
|
|
|
|
/**
|
|
* struct file_info - keeping track of file info while traversing the rddm
|
|
* table header
|
|
* @file_offset - current file offset
|
|
* @seg_idx - mhi buf seg array index
|
|
* @rem_seg_len - remaining length of the segment containing current file
|
|
*/
|
|
struct file_info {
|
|
u8 *file_offset;
|
|
u32 file_size;
|
|
u32 seg_idx;
|
|
u32 rem_seg_len;
|
|
};
|
|
|
|
/**
|
|
* struct reg_write_info - offload reg write info
|
|
* @reg_addr - register address
|
|
* @val - value to be written to register
|
|
* @chan - channel number
|
|
* @valid - entry is valid or not
|
|
*/
|
|
struct reg_write_info {
|
|
void __iomem *reg_addr;
|
|
u32 val;
|
|
bool valid;
|
|
};
|
|
|
|
/**
|
|
* struct mhi_private - For private variables of an MHI controller
|
|
*/
|
|
struct mhi_private {
|
|
struct list_head node;
|
|
struct mhi_controller *mhi_cntrl;
|
|
enum MHI_DEBUG_LEVEL log_lvl;
|
|
void *log_buf;
|
|
u32 saved_pm_state;
|
|
enum mhi_state saved_dev_state;
|
|
u32 m2_timeout_ms;
|
|
void *priv_data;
|
|
void __iomem *bw_scale_db;
|
|
int (*bw_scale)(struct mhi_controller *mhi_cntrl,
|
|
struct mhi_link_info *link_info);
|
|
phys_addr_t base_addr;
|
|
u32 numeric_id;
|
|
u32 bw_response;
|
|
struct mhi_sfr_info *sfr_info;
|
|
struct mhi_timesync *timesync;
|
|
|
|
/* reg write offload */
|
|
struct workqueue_struct *offload_wq;
|
|
struct work_struct reg_write_work;
|
|
struct reg_write_info *reg_write_q;
|
|
atomic_t write_idx;
|
|
u32 read_idx;
|
|
};
|
|
|
|
/**
|
|
* struct mhi_bus - For MHI controller debug
|
|
*/
|
|
struct mhi_bus {
|
|
struct list_head controller_list;
|
|
struct mutex lock;
|
|
};
|
|
|
|
/**
|
|
* struct mhi_sfr_info - For receiving MHI subsystem failure reason
|
|
*/
|
|
struct mhi_sfr_info {
|
|
void *buf_addr;
|
|
dma_addr_t dma_addr;
|
|
size_t len;
|
|
char *str;
|
|
unsigned int ccs;
|
|
struct completion completion;
|
|
};
|
|
|
|
/**
|
|
* struct mhi_timesync - For enabling use of MHI time synchronization feature
|
|
*/
|
|
struct mhi_timesync {
|
|
u64 (*time_get)(struct mhi_controller *mhi_cntrl);
|
|
int (*lpm_disable)(struct mhi_controller *mhi_cntrl);
|
|
int (*lpm_enable)(struct mhi_controller *mhi_cntrl);
|
|
void __iomem *time_reg;
|
|
void __iomem *time_db;
|
|
u32 int_sequence;
|
|
u64 local_time;
|
|
u64 remote_time;
|
|
bool db_pending;
|
|
struct completion completion;
|
|
spinlock_t lock; /* list protection */
|
|
struct list_head head;
|
|
struct mutex mutex;
|
|
};
|
|
|
|
/**
|
|
* struct tsync_node - Stores requests when using the timesync doorbell method
|
|
*/
|
|
struct tsync_node {
|
|
struct list_head node;
|
|
u32 sequence;
|
|
u64 remote_time;
|
|
struct mhi_device *mhi_dev;
|
|
void (*cb_func)(struct mhi_device *mhi_dev, u32 sequence,
|
|
u64 local_time, u64 remote_time);
|
|
};
|
|
|
|
#ifdef CONFIG_MHI_BUS_MISC
|
|
void mhi_misc_init(void);
|
|
void mhi_misc_exit(void);
|
|
int mhi_misc_init_mmio(struct mhi_controller *mhi_cntrl);
|
|
int mhi_misc_register_controller(struct mhi_controller *mhi_cntrl);
|
|
void mhi_misc_unregister_controller(struct mhi_controller *mhi_cntrl);
|
|
int mhi_misc_sysfs_create(struct mhi_controller *mhi_cntrl);
|
|
void mhi_misc_sysfs_destroy(struct mhi_controller *mhi_cntrl);
|
|
int mhi_process_misc_bw_ev_ring(struct mhi_controller *mhi_cntrl,
|
|
struct mhi_event *mhi_event, u32 event_quota);
|
|
int mhi_process_misc_tsync_ev_ring(struct mhi_controller *mhi_cntrl,
|
|
struct mhi_event *mhi_event, u32 event_quota);
|
|
void mhi_misc_mission_mode(struct mhi_controller *mhi_cntrl);
|
|
void mhi_misc_dbs_pending(struct mhi_controller *mhi_cntrl);
|
|
void mhi_misc_disable(struct mhi_controller *mhi_cntrl);
|
|
void mhi_misc_cmd_configure(struct mhi_controller *mhi_cntrl,
|
|
unsigned int type, u64 *ptr, u32 *dword0,
|
|
u32 *dword1);
|
|
void mhi_misc_cmd_completion(struct mhi_controller *mhi_cntrl,
|
|
unsigned int type, unsigned int ccs);
|
|
void mhi_write_offload_wakedb(struct mhi_controller *mhi_cntrl, int db_val);
|
|
void mhi_reset_reg_write_q(struct mhi_controller *mhi_cntrl);
|
|
void mhi_force_reg_write(struct mhi_controller *mhi_cntrl);
|
|
#else
|
|
static inline void mhi_misc_init(void)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_misc_exit(void)
|
|
{
|
|
}
|
|
|
|
static inline int mhi_misc_init_mmio(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int mhi_misc_register_controller(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void mhi_misc_unregister_controller(struct mhi_controller
|
|
*mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
static inline int mhi_misc_sysfs_create(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void mhi_misc_sysfs_destroy(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
static inline int mhi_process_misc_bw_ev_ring(struct mhi_controller *mhi_cntrl,
|
|
struct mhi_event *mhi_event, u32 event_quota)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int mhi_process_misc_tsync_ev_ring
|
|
(struct mhi_controller *mhi_cntrl,
|
|
struct mhi_event *mhi_event, u32 event_quota)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void mhi_misc_mission_mode(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_special_dbs_pending(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_misc_disable(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_misc_cmd_configure(struct mhi_controller *mhi_cntrl,
|
|
unsigned int type, u64 *ptr,
|
|
u32 *dword0, u32 *dword1)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_misc_cmd_completion(struct mhi_controller *mhi_cntrl,
|
|
unsigned int type, unsigned int ccs)
|
|
{
|
|
}
|
|
|
|
static inline void mhi_write_offload_wakedb(struct mhi_controller *mhi_cntrl,
|
|
int db_val)
|
|
{
|
|
}
|
|
|
|
void mhi_reset_reg_write_q(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
|
|
void mhi_force_reg_write(struct mhi_controller *mhi_cntrl)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#endif /* _MHI_CORE_MISC_H_ */
|