blob: 7d619cd4ccf0578e6dfbc278c45a1a96c69d2a7b [file] [log] [blame]
/*
* Copyright (C) 2012 Samsung Electronics.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef __MODEM_V1_H__
#define __MODEM_V1_H__
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#ifdef CONFIG_LINK_DEVICE_SHMEM
#include <linux/shm_ipc.h>
#endif
#define MAX_STR_LEN 256
#define MAX_NAME_LEN 64
#define MAX_DUMP_LEN 20
#define SMC_ID_CLK 0x82001011
#define SSS_CLK_ENABLE 0
#define SSS_CLK_DISABLE 1
enum modem_t {
IMC_XMM6260,
IMC_XMM6262,
VIA_CBP71,
VIA_CBP72,
VIA_CBP82,
SEC_CMC220,
SEC_CMC221,
SEC_SS222,
SEC_SS300,
SEC_SH222AP,
SEC_SS310AP,
QC_MDM6600,
QC_ESC6270,
QC_QSC6085,
SPRD_SC8803,
IMC_XMM7260,
DUMMY,
MAX_MODEM_TYPE
};
enum dev_format {
IPC_FMT,
IPC_RAW,
IPC_RFS,
IPC_MULTI_RAW,
IPC_BOOT,
IPC_DUMP,
IPC_CMD,
IPC_DEBUG,
MAX_DEV_FORMAT,
};
enum legacy_ipc_map {
IPC_MAP_FMT = 0,
#ifdef CONFIG_MODEM_IF_LEGACY_QOS
IPC_MAP_HPRIO_RAW,
#endif
IPC_MAP_NORM_RAW,
MAX_SIPC_MAP,
};
#define MAX_SIPC_CHANNELS 256 /* 2 ^ 8 */
#define MAX_LINK_CHANNELS 32 /* up to 32 channels */
enum modem_io {
IODEV_MISC,
IODEV_NET,
IODEV_DUMMY,
};
/* Caution!!
* Please make sure that below sequence is exactly matched with cbd.
* If you want one more link type, append it to the end of list.
*/
enum modem_link {
LINKDEV_UNDEFINED,
LINKDEV_MIPI,
LINKDEV_DPRAM,
LINKDEV_SPI,
LINKDEV_USB,
LINKDEV_HSIC,
LINKDEV_C2C,
LINKDEV_UART,
LINKDEV_PLD,
LINKDEV_SHMEM,
LINKDEV_LLI,
LINKDEV_MAX
};
#define LINKTYPE(modem_link) (1u << (modem_link))
enum modem_network {
UMTS_NETWORK,
CDMA_NETWORK,
TDSCDMA_NETWORK,
LTE_NETWORK,
MAX_MODEM_NETWORK
};
enum sipc_ver {
NO_SIPC_VER = 0,
SIPC_VER_40 = 40,
SIPC_VER_41 = 41,
SIPC_VER_42 = 42,
SIPC_VER_50 = 50,
MAX_SIPC_VER
};
enum sipc_ch_id {
SIPC_CH_ID_RAW_0 = 0, /*reserved*/
SIPC_CH_ID_CS_VT_DATA,
SIPC_CH_ID_CS_VT_CONTROL,
SIPC_CH_ID_CS_VT_AUDIO,
SIPC_CH_ID_CS_VT_VIDEO,
SIPC_CH_ID_RAW_5, /*reserved*/
SIPC_CH_ID_RAW_6, /*reserved*/
SIPC_CH_ID_CDMA_DATA,
SIPC_CH_ID_PCM_DATA,
SIPC_CH_ID_TRANSFER_SCREEN,
SIPC_CH_ID_PDP_0 = 10, /*ID:10*/
SIPC_CH_ID_PDP_1,
SIPC_CH_ID_PDP_2,
SIPC_CH_ID_PDP_3,
SIPC_CH_ID_PDP_4,
SIPC_CH_ID_PDP_5,
SIPC_CH_ID_PDP_6,
SIPC_CH_ID_PDP_7,
SIPC_CH_ID_PDP_8,
SIPC_CH_ID_PDP_9,
SIPC_CH_ID_PDP_10,
SIPC_CH_ID_PDP_11,
SIPC_CH_ID_PDP_12,
SIPC_CH_ID_PDP_13,
SIPC_CH_ID_PDP_14,
SIPC_CH_ID_BT_DUN, /*ID:25*/
SIPC_CH_ID_CIQ_DATA,
SIPC_CH_ID_PDP_17, /*reserved*/
SIPC_CH_ID_CPLOG1, /*ID:28*/
SIPC_CH_ID_CPLOG2, /*ID:29*/
SIPC_CH_ID_LOOPBACK1, /*ID:30*/
SIPC_CH_ID_LOOPBACK2, /*ID:31*/
SIPC_CH_ID_CASS = 35,
/* 32 ~ 214 are reserved */
SIPC5_CH_ID_BOOT_0 = 215,
SIPC5_CH_ID_BOOT_1,
SIPC5_CH_ID_BOOT_2,
SIPC5_CH_ID_BOOT_3,
SIPC5_CH_ID_BOOT_4,
SIPC5_CH_ID_BOOT_5,
SIPC5_CH_ID_BOOT_6,
SIPC5_CH_ID_BOOT_7,
SIPC5_CH_ID_BOOT_8,
SIPC5_CH_ID_BOOT_9,
SIPC5_CH_ID_DUMP_0 = 225,
SIPC5_CH_ID_DUMP_1,
SIPC5_CH_ID_DUMP_2,
SIPC5_CH_ID_DUMP_3,
SIPC5_CH_ID_DUMP_4,
SIPC5_CH_ID_DUMP_5,
SIPC5_CH_ID_DUMP_6,
SIPC5_CH_ID_DUMP_7,
SIPC5_CH_ID_DUMP_8,
SIPC5_CH_ID_DUMP_9,
SIPC5_CH_ID_FMT_0 = 235,
SIPC5_CH_ID_FMT_1,
SIPC5_CH_ID_FMT_2,
SIPC5_CH_ID_FMT_3,
SIPC5_CH_ID_FMT_4,
SIPC5_CH_ID_FMT_5,
SIPC5_CH_ID_FMT_6,
SIPC5_CH_ID_FMT_7,
SIPC5_CH_ID_FMT_8,
SIPC5_CH_ID_FMT_9,
SIPC5_CH_ID_RFS_0 = 245,
SIPC5_CH_ID_RFS_1,
SIPC5_CH_ID_RFS_2,
SIPC5_CH_ID_RFS_3,
SIPC5_CH_ID_RFS_4,
SIPC5_CH_ID_RFS_5,
SIPC5_CH_ID_RFS_6,
SIPC5_CH_ID_RFS_7,
SIPC5_CH_ID_RFS_8,
SIPC5_CH_ID_RFS_9,
SIPC5_CH_ID_MAX = 255
};
struct __packed multi_frame_control {
u8 id:7,
more:1;
};
enum io_mode {
PIO,
DMA
};
enum direction {
TX = 0,
UL = 0,
AP2CP = 0,
RX = 1,
DL = 1,
CP2AP = 1,
TXRX = 2,
ULDL = 2,
MAX_DIR = 2
};
enum read_write {
RD = 0,
WR = 1,
RDWR = 2
};
#define STR_CP_FAIL "cp_fail"
#define STR_CP_WDT "cp_wdt" /* CP watchdog timer */
/* You can define modem specific attribute here.
* It could be all the different behaviour between many modem vendor.
*/
enum link_attr_bit {
LINK_ATTR_SBD_IPC, /* IPC over SBD (from MIPI-LLI) */
LINK_ATTR_IPC_ALIGNED, /* IPC with 4-bytes alignment */
LINK_ATTR_IOSM_MESSAGE, /* IOSM message */
LINK_ATTR_DPRAM_MAGIC, /* DPRAM-style magic code validation */
/*--------------------------------------------------------------*/
LINK_ATTR_SBD_BOOT, /* BOOT over SBD */
LINK_ATTR_SBD_DUMP, /* DUMP over SBD */
LINK_ATTR_MEM_BOOT, /* BOOT over legacy memory-type I/F */
LINK_ATTR_MEM_DUMP, /* DUMP over legacy memory-type I/F */
LINK_ATTR_BOOT_ALIGNED, /* BOOT with 4-bytes alignment */
LINK_ATTR_DUMP_ALIGNED, /* DUMP with 4-bytes alignment */
/*--------------------------------------------------------------*/
LINK_ATTR_XMIT_BTDLR, /* Used to download CP bootloader */
};
#define LINK_ATTR(b) (0x1 << b)
enum iodev_attr_bit {
ATTR_SIPC4,
ATTR_SIPC5,
ATTR_CDC_NCM,
ATTR_MULTIFMT,
ATTR_HANDOVER,
ATTR_LEGACY_RFS,
ATTR_RX_FRAGMENT,
ATTR_SBD_IPC, /* IPC using SBD designed from MIPI-LLI */
ATTR_NO_LINK_HEADER, /* Link-layer header is not needed */
ATTR_NO_CHECK_MAXQ, /* no need to check rxq overflow condition */
ATTR_DUALSIM, /* support Dual SIM */
ATTR_OPTION_REGION, /* region & operator info */
ATTR_ZEROCOPY, /* suppoert Zerocopy : 0x1 << 12*/
};
#define IODEV_ATTR(b) (0x1 << b)
/**
* struct modem_io_t - declaration for io_device
* @name: device name
* @id: for SIPC4, contains format & channel information
* (id & 11100000b)>>5 = format (eg, 0=FMT, 1=RAW, 2=RFS)
* (id & 00011111b) = channel (valid only if format is RAW)
* for SIPC5, contains only 8-bit channel ID
* @format: device format
* @io_type: type of this io_device
* @links: list of link_devices to use this io_device
* for example, if you want to use DPRAM and USB in an io_device.
* .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB)
* @tx_link: when you use 2+ link_devices, set the link for TX.
* If define multiple link_devices in @links,
* you can receive data from them. But, cannot send data to all.
* TX is only one link_device.
* @app: the name of the application that will use this IO device
*
*/
struct modem_io_t {
char *name;
u32 id;
enum dev_format format;
enum modem_io io_type;
u32 links;
enum modem_link tx_link;
u32 attrs;
char *app;
char *option_region;
#if 1/*defined(CONFIG_LINK_DEVICE_MEMORY_SBD)*/
unsigned int ul_num_buffers;
unsigned int ul_buffer_size;
unsigned int dl_num_buffers;
unsigned int dl_buffer_size;
#endif
};
struct modemlink_pm_data {
char *name;
struct device *dev;
/* link power contol 2 types : pin & regulator control */
int (*link_ldo_enable)(bool);
unsigned int gpio_link_enable;
unsigned int gpio_link_active;
unsigned int gpio_link_hostwake;
unsigned int gpio_link_slavewake;
int (*link_reconnect)(void);
/* usb hub only */
int (*port_enable)(int, int);
int (*hub_standby)(void *);
void *hub_pm_data;
bool has_usbhub;
/* cpu/bus frequency lock */
atomic_t freqlock;
int (*freq_lock)(struct device *dev);
int (*freq_unlock)(struct device *dev);
int autosuspend_delay_ms; /* if zero, the default value is used */
void (*ehci_reg_dump)(struct device *);
};
struct modemlink_pm_link_activectl {
int gpio_initialized;
int gpio_request_host_active;
};
#ifdef CONFIG_LINK_DEVICE_SHMEM
enum shmem_type {
REAL_SHMEM,
C2C_SHMEM,
MAX_SHMEM_TYPE
};
struct modem_mbox {
unsigned int mbx_ap2cp_msg;
unsigned int mbx_cp2ap_msg;
unsigned int mbx_ap2cp_wakeup; /* CP_WAKEUP */
unsigned int mbx_cp2ap_wakeup; /* AP_WAKEUP */
unsigned int mbx_ap2cp_status; /* AP_STATUS */
unsigned int mbx_cp2ap_status; /* CP_STATUS */
unsigned int mbx_cp2ap_wakelock; /* Wakelock for VoLTE */
unsigned int mbx_cp2ap_ratmode; /* Wakelock for pcie */
unsigned int mbx_ap2cp_kerneltime; /* Kernel time */
unsigned int int_ap2cp_msg;
unsigned int int_ap2cp_active;
unsigned int int_ap2cp_wakeup;
unsigned int int_ap2cp_status;
unsigned int int_ap2cp_uart_noti;
unsigned int irq_cp2ap_msg;
unsigned int irq_cp2ap_active;
unsigned int irq_cp2ap_wakeup;
unsigned int irq_cp2ap_status;
unsigned int irq_cp2ap_wakelock;
unsigned int irq_cp2ap_rat_mode;
/* Performance request */
unsigned int mbx_ap2cp_perf_req;
unsigned int mbx_cp2ap_perf_req;
unsigned int mbx_cp2ap_perf_req_cpu;
unsigned int mbx_cp2ap_perf_req_mif;
unsigned int mbx_cp2ap_perf_req_int;
unsigned int int_ap2cp_perf_req;
unsigned int irq_cp2ap_perf_req;
unsigned int irq_cp2ap_perf_req_cpu;
unsigned int irq_cp2ap_perf_req_mif;
unsigned int irq_cp2ap_perf_req_int;
unsigned int mbx_ap2cp_lock_value;
/* Status Bit Info */
unsigned int sbi_lte_active_mask;
unsigned int sbi_lte_active_pos;
unsigned int sbi_cp_status_mask;
unsigned int sbi_cp_status_pos;
unsigned int sbi_cp2ap_wakelock_mask;
unsigned int sbi_cp2ap_wakelock_pos;
unsigned int sbi_cp2ap_rat_mode_mask;
unsigned int sbi_cp2ap_rat_mode_pos;
unsigned int sbi_pda_active_mask;
unsigned int sbi_pda_active_pos;
unsigned int sbi_ap_status_mask;
unsigned int sbi_ap_status_pos;
unsigned int sbi_ap2cp_kerneltime_sec_mask;
unsigned int sbi_ap2cp_kerneltime_sec_pos;
unsigned int sbi_ap2cp_kerneltime_usec_mask;
unsigned int sbi_ap2cp_kerneltime_usec_pos;
unsigned int sbi_uart_noti_mask;
unsigned int sbi_uart_noti_pos;
unsigned int sbi_crash_type_mask;
unsigned int sbi_crash_type_pos;
/* Clk table Info */
unsigned int *ap_clk_table;
unsigned int ap_clk_cnt;
unsigned int *mif_clk_table;
unsigned int mif_clk_cnt;
unsigned int *int_clk_table;
unsigned int int_clk_cnt;
};
#endif
/* platform data */
struct modem_data {
char *name;
unsigned int gpio_cp_on;
unsigned int gpio_cp_off;
unsigned int gpio_reset_req_n;
unsigned int gpio_cp_reset;
/* for broadcasting AP's PM state (active or sleep) */
unsigned int gpio_pda_active;
/* for checking aliveness of CP */
unsigned int gpio_phone_active;
unsigned int irq_phone_active;
/* for AP-CP IPC interrupt */
unsigned int gpio_ipc_int2ap;
unsigned int irq_ipc_int2ap;
unsigned long irqf_ipc_int2ap; /* IRQ flags */
unsigned int gpio_ipc_int2cp;
/* for AP-CP power management (PM) handshaking */
unsigned int gpio_ap_wakeup;
unsigned int irq_ap_wakeup;
unsigned int gpio_ap_status;
unsigned int gpio_cp_wakeup;
unsigned int gpio_cp_status;
unsigned int irq_cp_status;
/* for USB/HSIC PM */
unsigned int gpio_host_wakeup;
unsigned int irq_host_wakeup;
unsigned int gpio_host_active;
unsigned int gpio_slave_wakeup;
unsigned int gpio_cp_dump_int;
unsigned int gpio_ap_dump_int;
unsigned int gpio_flm_uart_sel;
unsigned int gpio_cp_warm_reset;
unsigned int gpio_sim_detect;
unsigned int irq_sim_detect;
#ifdef CONFIG_LINK_DEVICE_SHMEM
struct modem_mbox *mbx;
struct mem_link_device *mld;
/* MIF buffer information */
unsigned int buff_offset;
unsigned int buff_size;
/* buff pool 2nd information */
unsigned long int bufpool_2nd_base;
unsigned int bufpool_2nd_size;
#endif
/* Switch with 2 links in a modem */
unsigned int gpio_link_switch;
/* Modem component */
enum modem_network modem_net;
enum modem_t modem_type;
u32 link_types;
char *link_name;
unsigned long link_attrs; /* Set of link_attr_bit flags */
/* SIPC version */
enum sipc_ver ipc_version;
/* Information of IO devices */
unsigned int num_iodevs;
struct modem_io_t *iodevs;
/* Modem link PM support */
struct modemlink_pm_data *link_pm_data;
/* Handover with 2+ modems */
bool use_handover;
/* SIM Detect polarity */
bool sim_polarity;
void (*gpio_revers_bias_clear)(void);
void (*gpio_revers_bias_restore)(void);
};
struct modem_irq {
spinlock_t lock;
unsigned int num;
char name[MAX_NAME_LEN];
unsigned long flags;
bool active;
bool registered;
};
#define MODEM_BOOT_DEV_SPI "spi_boot_link"
struct modem_boot_spi_platform_data {
const char *name;
unsigned int gpio_cp_status;
};
struct modem_boot_spi {
struct miscdevice misc_dev;
struct spi_device *spi_dev;
struct mutex lock;
unsigned int gpio_cp_status;
};
#define to_modem_boot_spi(misc) \
container_of(misc, struct modem_boot_spi, misc_dev);
#ifdef CONFIG_OF
#define mif_dt_read_enum(np, prop, dest) \
do { \
u32 val; \
if (of_property_read_u32(np, prop, &val)) { \
mif_err("%s is not defined\n", prop); \
return -EINVAL; \
} \
dest = (__typeof__(dest))(val); \
} while (0)
#define mif_dt_read_bool(np, prop, dest) \
do { \
u32 val; \
if (of_property_read_u32(np, prop, &val)) { \
mif_err("%s is not defined\n", prop); \
return -EINVAL; \
} \
dest = val ? true : false; \
} while (0)
#define mif_dt_read_string(np, prop, dest) \
do { \
if (of_property_read_string(np, prop, \
(const char **)&dest)) { \
mif_err("%s is not defined\n", prop); \
return -EINVAL; \
} \
} while (0)
#define mif_dt_read_u32(np, prop, dest) \
do { \
u32 val; \
if (of_property_read_u32(np, prop, &val)) { \
mif_err("%s is not defined\n", prop); \
return -EINVAL; \
} \
dest = val; \
} while (0)
#define mif_dt_read_u32_noerr(np, prop, dest) \
do { \
u32 val; \
if (!of_property_read_u32(np, prop, &val)) \
dest = val; \
} while (0)
#endif
#define LOG_TAG "mif: "
#define FUNC (__func__)
#define CALLER (__builtin_return_address(0))
#define mif_err_limited(fmt, ...) \
printk_ratelimited(KERN_ERR LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__)
#define mif_err(fmt, ...) \
pr_err(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__)
#define mif_debug(fmt, ...) \
pr_debug(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__)
#define mif_info(fmt, ...) \
pr_info(LOG_TAG "%s: " pr_fmt(fmt), __func__, ##__VA_ARGS__)
#define mif_trace(fmt, ...) \
printk(KERN_DEBUG "mif: %s: %d: called(%pF): " fmt, \
__func__, __LINE__, __builtin_return_address(0), ##__VA_ARGS__)
#endif