diff options
author | Dorian Snyder <dastin1015@gmail.com> | 2013-06-12 02:24:45 -0700 |
---|---|---|
committer | Dorian Snyder <dastin1015@gmail.com> | 2013-06-20 00:06:04 -0700 |
commit | 4b2308ce699b9c599dd6e6acf57ac11f483381d9 (patch) | |
tree | 4c31179b06d094887b1c8ca70264cf8f184a5981 /drivers/dpram/raffaello | |
parent | 855d6a6c1f7c54ef073caac3f6c5f9b1ed72eb4d (diff) | |
download | kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.zip kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.gz kernel_samsung_smdk4412-4b2308ce699b9c599dd6e6acf57ac11f483381d9.tar.bz2 |
d710: initial support for the Epic 4G Touch (SPH-D710)
Change-Id: Iafbd9fb45253b02d539ac0ba114f57b3bf9eeed4
Diffstat (limited to 'drivers/dpram/raffaello')
-rwxr-xr-x | drivers/dpram/raffaello/dpram.c | 3747 | ||||
-rwxr-xr-x | drivers/dpram/raffaello/dpram.h | 418 | ||||
-rw-r--r-- | drivers/dpram/raffaello/dpram_recovery.c | 1527 | ||||
-rw-r--r-- | drivers/dpram/raffaello/dpram_recovery.h | 132 |
4 files changed, 5824 insertions, 0 deletions
diff --git a/drivers/dpram/raffaello/dpram.c b/drivers/dpram/raffaello/dpram.c new file mode 100755 index 0000000..77e4a03 --- /dev/null +++ b/drivers/dpram/raffaello/dpram.c @@ -0,0 +1,3747 @@ +/**************************************************************************** +** +** COPYRIGHT(C) : Samsung Electronics Co.Ltd, 2006-2010 ALL RIGHTS RESERVED +** +** IDPRAM Device Driver +** +****************************************************************************/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/irq.h> +#include <linux/poll.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/hardware.h> + +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif /* CONFIG_PROC_FS */ + +#include <linux/workqueue.h> +#include <linux/wakelock.h> +#include <linux/miscdevice.h> +#include <linux/netdevice.h> +#ifdef CONFIG_SEC_DEBUG +#include <linux/kernel_sec_common.h> +#endif + +#include "dpram.h" +#include <mach/system.h> +#include <mach/sec_debug.h> + +/***************************************************************************/ +/* GPIO SETTING */ +/***************************************************************************/ +#include <mach/gpio.h> + +int sec_debug_dpram(void); + +/* Added to store irq num */ +int dpram_irq; +int dpram_wakeup_irq; +int phone_active_irq; +int cp_dump_irq; + +#define GPIO_QSC_INT GPIO_C210_DPRAM_INT_N +#define IRQ_QSC_INT GPIO_QSC_INT + +#define IRQ_CP_DUMP_INT GPIO_CP_DUMP_INT + +#ifdef IRQ_DPRAM_AP_INT_N +#undef IRQ_DPRAM_AP_INT_N +#endif +#define IRQ_DPRAM_AP_INT_N IRQ_MODEM_IF + +#define PRINT_DPRAM_PWR_CTRL + +/* +** Definitions for CP RAMDUMP +*/ +#if 1 +#define CMD_CP_RAMDUMP_START_REQ 0x9200 +#define CMD_CP_RAMDUMP_START_RESP 0x0300 +#define CMD_CP_RAMDUMP_SEND_REQ 0x9400 +#define CMD_CP_RAMDUMP_SEND_RESP 0x0500 +#define CMD_CP_RAMDUMP_SEND_DONE_REQ 0x9600 +#define CMD_CP_RAMDUMP_SEND_DONE_RESP 0x0700 + +#define MASK_CMD_RESULT_FAIL 0x0002 +#define MASK_CMD_RESULT_SUCCESS 0x0001 + +/* MailBox Message */ +#define QSC_UPLOAD_MODE (0x444D554C) +#define QSC_UPLOAD_MODE_COMPLETE (0xABCDEF90) + +#define CP_RAMDUMP_MAGIC_CODE_SIZE 4 +#define CP_RAMDUMP_HEADER_SIZE 12 +#define CP_RAMDUMP_BUFFER_SIZE 16364 +#define DPRAM_CP_HEADER_START_ADDRESS (DPRAM_VBASE + CP_RAMDUMP_MAGIC_CODE_SIZE) +#define DPRAM_CP_RAMDUMP_START_ADDRESS (DPRAM_CP_HEADER_START_ADDRESS + CP_RAMDUMP_HEADER_SIZE) + +#define MASK_CMD_VALID 0x8000 +#define MASK_PDA_CMD 0x1000 +#define MASK_PHONE_CMD 0x2000 + +#define RAMDUMP_WAIT_TIMEOUT 5*HZ + +typedef struct _DumpCMDHeader +{ + u32 addr; + u32 size; + u32 copyto_offset; +} DumpCMDHeader; + +typedef struct +{ + int index; + unsigned long start_addr; + unsigned long end_addr; +} s_cp_mem_region; + +typedef struct +{ + unsigned long dram_base_addr; + s_cp_mem_region cp_mem_region[16]; +} s_cp_mem_info; + +s_cp_mem_info cp_mem_info = { + 0x40000000, + { + {0, 0x00000000, 0x01FFFFFF }, + } +}; + +struct dpram { + struct class *class; + struct device *dev; + struct cdev cdev; + dev_t devid; + + wait_queue_head_t waitq; + struct fasync_struct *async_queue; + u32 mailbox; + + unsigned long base; + unsigned long size; + void __iomem *mmio; + + int irq; + + struct completion comp; + atomic_t ref_sem; + unsigned long flags; + + const struct attribute_group *group; +}; + +struct dpram *dpram_dev; + +struct completion wait_dump_data; + +static int g_irq_mask = 0; + +static u32 dump_rx_total = 0; +#endif + + +/* =========================================================================== +** +** L O C A L - V A R I A B L E S +** +** =========================================================================*/ + +/* + * GLOBALS + */ +volatile void __iomem *idpram_base = NULL; +volatile IDPRAM_SFR __iomem *idpram_sfr_base = NULL; + +static volatile u16 *dpram_mbx_BA; +static volatile u16 *dpram_mbx_AB; + +struct wake_lock dpram_wake_lock = {.name = NULL}; +static atomic_t dpram_write_lock; +static atomic_t dpram_read_lock; + +static int g_phone_sync = 0; +static int g_dump_on = 0; +static int g_dpram_wpend = IDPRAM_WPEND_UNLOCK; +struct completion g_complete_dpramdown; +static int g_cp_reset_cnt = 0; +static int g_phone_power_off_sequence = 0; + +static struct tty_driver *dpram_tty_driver; +static struct tty_struct *dpram_tty[MAX_INDEX]; +static struct ktermios *dpram_termios[MAX_INDEX]; +static struct ktermios *dpram_termios_locked[MAX_INDEX]; +static struct pdp_info *pdp_table[MAX_PDP_CONTEXT]; + +static dpram_tasklet_data_t dpram_tasklet_data[MAX_INDEX]; + +static dpram_device_t dpram_table[MAX_INDEX] = +{ + { + .in_head_addr = DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS, + .in_tail_addr = DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS, + .in_buff_addr = DPRAM_PHONE2PDA_FORMATTED_BUFFER_ADDRESS, + .in_buff_size = DPRAM_PHONE2PDA_FORMATTED_BUFFER_SIZE, + .in_head_saved = 0, + .in_tail_saved = 0, + + .out_head_addr = DPRAM_PDA2PHONE_FORMATTED_HEAD_ADDRESS, + .out_tail_addr = DPRAM_PDA2PHONE_FORMATTED_TAIL_ADDRESS, + .out_buff_addr = DPRAM_PDA2PHONE_FORMATTED_BUFFER_ADDRESS, + .out_buff_size = DPRAM_PDA2PHONE_FORMATTED_BUFFER_SIZE, + .out_head_saved = 0, + .out_tail_saved = 0, + + .mask_req_ack = INT_MASK_REQ_ACK_F, + .mask_res_ack = INT_MASK_RES_ACK_F, + .mask_send = INT_MASK_SEND_F, + }, + { + .in_head_addr = DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS, + .in_tail_addr = DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS, + .in_buff_addr = DPRAM_PHONE2PDA_RAW_BUFFER_ADDRESS, + .in_buff_size = DPRAM_PHONE2PDA_RAW_BUFFER_SIZE, + .in_head_saved = 0, + .in_tail_saved = 0, + + .out_head_addr = DPRAM_PDA2PHONE_RAW_HEAD_ADDRESS, + .out_tail_addr = DPRAM_PDA2PHONE_RAW_TAIL_ADDRESS, + .out_buff_addr = DPRAM_PDA2PHONE_RAW_BUFFER_ADDRESS, + .out_buff_size = DPRAM_PDA2PHONE_RAW_BUFFER_SIZE, + .out_head_saved = 0, + .out_tail_saved = 0, + + .mask_req_ack = INT_MASK_REQ_ACK_R, + .mask_res_ack = INT_MASK_RES_ACK_R, + .mask_send = INT_MASK_SEND_R, + }, +}; + +static unsigned int __log_level__ = (DL_IPC|DL_WARN|DL_NOTICE|DL_INFO|DL_DEBUG); + +#if defined(PRINT_DPRAM_WRITE) || defined(PRINT_DPRAM_READ) +static char print_buff[128]; +#endif + +static atomic_t raw_txq_req_ack_rcvd; +static atomic_t fmt_txq_req_ack_rcvd; +struct delayed_work phone_active_work; + +/* For Dual Core*/ +static DEFINE_SPINLOCK(mux_tty_lock); + + +/* +** TASKLET DECLARATIONs +*/ +static void res_ack_tasklet_handler(unsigned long data); +static void fmt_rcv_tasklet_handler(unsigned long data); +static void raw_rcv_tasklet_handler(unsigned long data); + +static DECLARE_TASKLET(fmt_send_tasklet, fmt_rcv_tasklet_handler, 0); +static DECLARE_TASKLET(raw_send_tasklet, raw_rcv_tasklet_handler, 0); +static DECLARE_TASKLET(fmt_res_ack_tasklet, res_ack_tasklet_handler, (unsigned long)&dpram_table[FORMATTED_INDEX]); +static DECLARE_TASKLET(raw_res_ack_tasklet, res_ack_tasklet_handler, (unsigned long)&dpram_table[RAW_INDEX]); +static DEFINE_MUTEX(pdp_lock); + + +/* +** FUNCTION PROTOTYPEs +*/ +static void dpram_drop_data(dpram_device_t *device); +static int kernel_sec_dump_cp_handle2(void); +static int dpram_phone_getstatus(void); +static void dpram_send_mbx_BA(u16 irq_mask); +static void dpram_send_mbx_BA_cmd(u16 irq_mask); +static void dpram_power_down(void); +static void dpram_powerup_start(void); +static int register_interrupt_handler(void); +static irqreturn_t dpram_irq_handler(int irq, void *dev_id); + + +static inline struct pdp_info * pdp_get_dev(u8 id); +static inline void check_pdp_table(const char*, int); +static void cmd_error_display_handler(void); + + +#ifdef _ENABLE_ERROR_DEVICE +static unsigned int dpram_err_len = 0; +static char dpram_err_buf[DPRAM_ERR_MSG_LEN]; +static unsigned int dpram_err_cause = 0; + +static unsigned int dpram_dump_len = 0; +static char cp_ramdump_buff[16384]; + +struct class *dpram_err_class; +struct class *dpram_dump_class; + +static DECLARE_WAIT_QUEUE_HEAD(dpram_err_wait_q); +static DECLARE_WAIT_QUEUE_HEAD(dpram_dump_wait_q); + +static struct fasync_struct *dpram_err_async_q; +static struct fasync_struct *dpram_dump_async_q; + +extern void usb_switch_mode(int); +#ifdef CONFIG_SEC_DEBUG +extern int get_sec_debug_level(void); +#endif +#endif /* _ENABLE_ERROR_DEVICE */ + + +#ifndef DISABLE_IPC_DEBUG +typedef struct { + unsigned char start_flag; + unsigned char hdlc_length[2]; + unsigned char hdlc_control; + unsigned char ipc_length[2]; + unsigned char msg_seq; + unsigned char ack_seq; + unsigned char main_cmd; + unsigned char sub_cmd; + unsigned char cmd_type; + unsigned char parameter[1024]; +} dpram_fmt_frame; +#endif + + +#if 1 +u32 dpram_write_magic_code(u32 code) +{ + u32 address = 0; + u32 value = 0; + + address = (u32)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS); + + LOGA("Code : 0x%08x, Magic code address : 0x%08x\n", code, address); + + memcpy_toio((void *)address, (void *)&code, 4); + memcpy_fromio((void *)&value, (void *)address, 4); + + LOGA("DPRAM Read Magic = 0x%08x\n", value); + + if (value != code) + LOGE("value != code\n"); + + return (value == code); +} + +static void DRV_Setting_ModemUploadMode(void) +{ + + dpram_write_magic_code(QSC_UPLOAD_MODE); +} + +static void DRV_Wait_ModemInit(void) +{ + + while (!gpio_get_value(GPIO_QSC_PHONE_ACTIVE)) { + msleep(100); + printk("."); + } + printk("\n"); +} + +static inline void dpram_clear_modem_command(void) +{ + iowrite16(0, (void*)(DPRAM_VBASE + DPRAM_PHONE2PDA_INTERRUPT_ADDRESS)); +} + +static inline u16 dpram_read_command(void) +{ + return ioread16((void*)(DPRAM_VBASE + DPRAM_PHONE2PDA_INTERRUPT_ADDRESS)); +} + +static void dpram_send_command(u16 nCmd) +{ + dpram_clear_modem_command(); + iowrite16(nCmd, (void*)(DPRAM_VBASE + DPRAM_PDA2PHONE_INTERRUPT_ADDRESS)); +} + +/* return value +// -1 : false +// 0 : continue +// 1 : true */ +#define CMD_FALSE -1 +#define CMD_RETRY 0 +#define CMD_TRUE 1 + +static u32 check_command(u16 intr, u16 mask) +{ + if (intr == 0) { + return CMD_RETRY; + } else { + if ((intr & MASK_CMD_VALID) != MASK_CMD_VALID) { + return CMD_RETRY; + } + else if ((intr & MASK_PDA_CMD) == MASK_PDA_CMD) { + return CMD_RETRY; + } + else if ((intr & MASK_PHONE_CMD) == MASK_PHONE_CMD) { + if ((intr & mask) == mask) + return CMD_TRUE; + else + return CMD_FALSE; + } + else + return CMD_RETRY; + } +} + +static u16 dpram_wait_response(u16 nCmd) +{ + u16 intr, ret; + int i; + + for (i = 0; i < 100; i++) + { + intr = dpram_read_command(); + ret = check_command(intr, nCmd); + if(ret == CMD_TRUE) + return CMD_TRUE; + else if(ret == CMD_FALSE) + return CMD_FALSE; + wait_for_completion_interruptible_timeout(&wait_dump_data, (HZ/100)); + init_completion(&wait_dump_data); + } + return CMD_RETRY; +} + +static void dpram_clear_response(void) +{ + init_completion(&wait_dump_data); + IDPRAM_INT_CLEAR(); + dpram_clear_modem_command(); +} + +static void _Request_ModemData(u32 addr, u32 size) +{ + DumpCMDHeader header; + u32 rx_required = 0; + int ret = 0; + + memset(&header, 0, sizeof(header)); + + rx_required = min(size - dump_rx_total, (u32)CP_RAMDUMP_BUFFER_SIZE); + + header.addr = addr + dump_rx_total; + header.size = rx_required; + header.copyto_offset = 0x38000010; + + memcpy_toio((void*)DPRAM_CP_HEADER_START_ADDRESS, (void*)&header, sizeof(header)); + + /* Wait for ACK */ + dpram_send_command(CMD_CP_RAMDUMP_SEND_REQ); + ret = dpram_wait_response(CMD_CP_RAMDUMP_SEND_RESP|MASK_CMD_RESULT_SUCCESS); + if (!ret) { + LOGE("Failed in dpram_wait_response()!!!\n"); + return; + } + dpram_clear_response(); + + /* Copy dump from DPRAM to local buffer */ + memcpy_fromio((void*)cp_ramdump_buff, (void*)DPRAM_CP_RAMDUMP_START_ADDRESS, CP_RAMDUMP_BUFFER_SIZE); + + /* Prepare to pass the dump data to RIL */ + dpram_dump_len = rx_required; + + dump_rx_total += rx_required; +} + +static void setup_cp_ramdump(void) +{ + DRV_Setting_ModemUploadMode(); + DRV_Wait_ModemInit(); +} + +static void start_cp_ramdump(void) +{ + int i, ret; + + for (i = 0; i < 30; i++) + { + dpram_send_command(CMD_CP_RAMDUMP_START_REQ); + ret = dpram_wait_response(CMD_CP_RAMDUMP_START_RESP|MASK_CMD_RESULT_SUCCESS); + if (ret == CMD_TRUE) { + LOGA("succeeded in dpram_wait_response()!!!\n"); + dpram_clear_response(); + return; + } else if (ret == CMD_FALSE) { + LOGE("Failed in dpram_wait_response()!!!\n"); + dpram_clear_response(); + return; + } + LOGA("RETRY is required in dpram_wait_response()!!!\n"); + } + + LOGE("Failed in dpram_wait_response()!!!\n"); + dpram_clear_response(); +} + +static void receive_cp_ramdump(void) +{ + u32 dump_start_addr, dump_end_addr, dump_size; + + dump_start_addr = cp_mem_info.cp_mem_region[0].start_addr; + dump_end_addr = cp_mem_info.cp_mem_region[0].end_addr; + dump_size = (dump_end_addr - dump_start_addr) + 1; + + /* read modem RAMDUMP data */ + _Request_ModemData(dump_start_addr, dump_size); +} + +static void close_cp_ramdump(void) +{ + int ret; + + dpram_send_command(CMD_CP_RAMDUMP_SEND_DONE_REQ); + ret = dpram_wait_response(CMD_CP_RAMDUMP_SEND_DONE_RESP|MASK_CMD_RESULT_SUCCESS); + if (!ret) { + LOGE("Failed in dpram_wait_response()!!!\n"); + return; + } + LOGA("succeeded in dpram_wait_response()!!!\n"); + dpram_clear_response(); +} +#endif + + +/* +** tty related functions. +*/ +static inline void dpram_byte_align(unsigned long dest, unsigned long src) +{ + volatile u16 *p_dest; + u16 *p_src; + + if ( (dest & 1) && (src & 1) ) + { + p_dest = (u16 *)(dest - 1); + p_src = (u16 *)(src - 1); + + *p_dest = (*p_dest & 0x00FF) | (*p_src & 0xFF00); + } + else if ( (dest & 1) && !(src & 1) ) + { + p_dest = (u16 *)(dest - 1); + p_src = (u16 *)src; + *p_dest = (*p_dest & 0x00FF) | ((*p_src << 8) & 0xFF00); + } + else if ( !(dest & 1) && (src & 1) ) + { + p_dest = (u16 *)dest; + p_src = (u16 *)(src - 1); + *p_dest = (*p_dest & 0xFF00) | ((*p_src >> 8) & 0x00FF); + } + else //if ( !(dest & 1) && !(src & 1) ) + { + p_dest = (u16 *)dest; + p_src = (u16 *)src; + *p_dest = (*p_dest & 0xFF00) | (*p_src & 0x00FF); + } +#if 0 + else + { + LOGE("oops.~\n"); + } +#endif +} + +static inline void _memcpy(void *p_dest, const void *p_src, int size) +{ + unsigned long dest = (unsigned long)p_dest; + unsigned long src = (unsigned long)p_src; + + if (size <= 0) + return; + + if (dest & 1) + { + /* If the destination address is odd, store the first byte at first.*/ + dpram_byte_align(dest, src); + dest++, src++; + size--; + } + + if (size & 1) + { + /* If the size is odd, store the last byte at first.*/ + dpram_byte_align(dest + size - 1, src + size - 1); + size--; + } + + if (src & 1) + { + volatile u16 *d = (u16 *)dest; + unsigned char *s = (u8 *)src; + + size >>= 1; + + while (size--) + { + *d++ = s[0] | (s[1] << 8); + s += 2; + } + } + else + { + volatile u16 *d = (u16 *)dest; + u16 *s = (u16 *)src; + + size >>= 1; + + while (size--) + { + *d++ = *s++; + } + } +} + +/* Note the use of non-standard return values (0=match, 1=no-match) */ +static inline int _memcmp(u8 *dest, u8 *src, int size) +{ + while( size-- ) + { + if( *dest++ != *src++ ) + return 1 ; + } + + return 0 ; +} + + +#define WRITE_TO_DPRAM(dest, src, size) \ + _memcpy((void *)(DPRAM_VBASE + dest), src, size) + +#define READ_FROM_DPRAM(dest, src, size) \ + _memcpy(dest, (void *)(DPRAM_VBASE + src), size) + + +static inline int WRITE_TO_DPRAM_VERIFY(u32 dest, void *src, int size) +{ + int cnt = 3; + + while (cnt--) + { + _memcpy((void *)(DPRAM_VBASE + dest), (void *)src, size); + + if (!_memcmp((u8 *)(DPRAM_VBASE + dest), (u8 *)src, size)) + return 0; + } + + return -1; +} + +static inline int READ_FROM_DPRAM_VERIFY(void *dest, u32 src, int size) +{ + int cnt = 3; + + while (cnt--) + { + _memcpy((void *)dest, (void *)(DPRAM_VBASE + src), size); + + if (!_memcmp((u8 *)dest, (u8 *)(DPRAM_VBASE + src), size)) + return 0; + } + + return -1; +} + +static int dpram_lock_write(const char* func) +{ + int lock_value; + + lock_value = (g_dpram_wpend == IDPRAM_WPEND_LOCK) ? -3 : atomic_inc_return(&dpram_write_lock); + if ( lock_value != 1 ) + LOGE("lock_value (%d) != 1\n", lock_value); + + return lock_value; +} + +static void dpram_unlock_write(const char* func) +{ + int lock_value; + + lock_value = atomic_dec_return(&dpram_write_lock); + + if ( lock_value != 0 ) + LOGE("lock_value (%d) != 0\n", lock_value); +} + +// TODO: +// because it is dpram device, I think read_lock don't need but I will use for holding wake_lock +static int dpram_get_lock_read(void) +{ + return atomic_read(&dpram_read_lock); +} + +static int dpram_lock_read(const char* func) +{ + int lock_value; + + lock_value = atomic_inc_return(&dpram_read_lock); + if(lock_value !=1) + LOGE("(%s, lock) lock_value: %d\n", func, lock_value); + wake_lock_timeout(&dpram_wake_lock, HZ*6); + return 0; +} + +static void dpram_unlock_read(const char* func) +{ + int lock_value; + + lock_value = atomic_dec_return(&dpram_read_lock); + + if(lock_value !=0) + LOGE("(%s, lock) lock_value: %d\n", func, lock_value); + + wake_unlock(&dpram_wake_lock); +} + + +#if defined(PRINT_DPRAM_WRITE) || defined(PRINT_DPRAM_READ) +static void dpram_print_packet(char *buf, int len) +{ + int i = 0; + LOGA("len = %d\n", len); + + print_buff[0] = '\0'; + + for (i = 0; i < len; i++) + { + sprintf((print_buff + (i%16)*3), "%02x \0", *((char *)buf + i)); + if ( (i%16) == 15 ) + { + LOGA("%s\n", print_buff); + print_buff[0] = '\0'; + } + } + + if ( strlen(print_buff) ) + { + LOGA("%s\n", print_buff); + } +} +#endif /*PRINT_DPRAM_WRITE || PRINT_DPRAM_READ*/ + +static int dpram_write(dpram_device_t *device, const unsigned char *buf, int len) +{ + int retval = 0; + int size = 0; + u16 head, tail, magic, access ; + u16 irq_mask = 0; + struct pdp_hdr *pdp_hdr_ptr = (struct pdp_hdr *)(buf + 1); + int curr_pkt_len = 0, free_space = 0; + + //PRINT_FUNC(); +#ifdef PRINT_DPRAM_WRITE + PRINT_FUNC(); + dpram_print_packet(buf, len); +#endif + + if (g_dump_on) { + LOGA("g_dump_on == 1\n"); + return 0; + } + + // If the phone is down, let's reset everything and fail the write. +#ifdef CDMA_IPC_C210_IDPRAM + magic = ioread16((void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + access = ioread16((void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); +#else + READ_FROM_DPRAM_VERIFY(&magic, DPRAM_MAGIC_CODE_ADDRESS, sizeof(magic)); + READ_FROM_DPRAM_VERIFY(&access, DPRAM_ACCESS_ENABLE_ADDRESS, sizeof(access)); +#endif + + /* Gaudi : modified ril power off sequence */ + //if (g_phone_sync != 1 || !access || magic != 0xAA) + if (!access || magic != 0xAA) + { + LOGE("Phone has not booted yet!!! (phone_sync = %d)\n", g_phone_sync); + return -EFAULT; + } + + if ( dpram_lock_write(__func__) < 0 ) + { + return -EAGAIN; + } + +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + device->out_head_addr)); + tail = ioread16((void *)(DPRAM_VBASE + device->out_tail_addr)); +#else + READ_FROM_DPRAM_VERIFY(&head, device->out_head_addr, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, device->out_tail_addr, sizeof(tail)); +#endif + + // Make sure the queue tail pointer is valid. + if( tail >= device->out_buff_size || head >= device->out_buff_size ) + { + head = tail = 0; +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(head, (void *)(DPRAM_VBASE + device->out_head_addr)); + iowrite16(tail, (void *)(DPRAM_VBASE + device->out_tail_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->out_head_addr, &head, sizeof(head)); + WRITE_TO_DPRAM_VERIFY(device->out_tail_addr, &tail, sizeof(tail)); +#endif + dpram_unlock_write(__func__); + return 0 ; + } + +#ifdef PRINT_DPRAM_WRITE + LOGA("head: %d, tail: %d\n", head, tail); +#endif + + /* check free space */ + curr_pkt_len = pdp_hdr_ptr->len + 2; /*include SOF/EOF*/ + free_space = (head < tail) ? tail-head -1 : device->out_buff_size + tail - head - 1; + + if (curr_pkt_len > free_space) { + LOGE("WRITE: No space in Q, curr_pkt_len[%d] free_space[%d] head[%d] tail[%d]\n", + curr_pkt_len, free_space, head, tail); + dpram_unlock_write(__func__); + return -EAGAIN; + } + + // +++++++++ head ---------- tail ++++++++++ // + if (head < tail) { + size = tail - head - 1; + size = (len > size) ? size : len; + WRITE_TO_DPRAM(device->out_buff_addr + head, buf, size); + retval = size; + } + + // tail +++++++++++++++ head --------------- // + else if (tail == 0) { + size = device->out_buff_size - head - 1; + size = (len > size) ? size : len; + WRITE_TO_DPRAM(device->out_buff_addr + head, buf, size); + retval = size; + } + + // ------ tail +++++++++++ head ------------ // + else { + size = device->out_buff_size - head; + size = (len > size) ? size : len; + WRITE_TO_DPRAM(device->out_buff_addr + head, buf, size); + retval = size; + + if (len > retval) { + size = (len - retval > tail - 1) ? tail - 1 : len - retval; + WRITE_TO_DPRAM(device->out_buff_addr, buf + retval, size); + retval += size; + } + } + + /* @LDK@ calculate new head */ + head = (u16)((head + retval) % device->out_buff_size); +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(head, (void *)(DPRAM_VBASE + device->out_head_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->out_head_addr, &head, sizeof(head)); +#endif + device->out_head_saved = head; + device->out_tail_saved = tail; + + /* @LDK@ send interrupt to the phone, if.. */ + irq_mask = INT_MASK_VALID; + + if (retval > 0) + irq_mask |= device->mask_send; + + if (len > retval) + irq_mask |= device->mask_req_ack; + + dpram_unlock_write(__func__); + dpram_send_mbx_BA(irq_mask); + + return retval; +} + +static inline int dpram_tty_insert_data(dpram_device_t *device, const u8 *psrc, u16 size) +{ +#define CLUSTER_SEGMENT 1500 + + u16 copied_size = 0; + int retval = 0; + +#ifdef PRINT_DPRAM_READ + dpram_print_packet(psrc, size); +#endif + + if ( size > CLUSTER_SEGMENT && (device->serial.tty->index == 1) ) + { + while (size) + { + copied_size = (size > CLUSTER_SEGMENT) ? CLUSTER_SEGMENT : size; + tty_insert_flip_string(device->serial.tty, psrc + retval, copied_size); + + size -= copied_size; + retval += copied_size; + } + + return retval; + } + + return tty_insert_flip_string(device->serial.tty, psrc, size); +} + +static int dpram_read_fmt(dpram_device_t *device, const u16 non_cmd) +{ + int retval = 0; + int retval_add = 0; + int size = 0; + u16 head, tail; + + dpram_lock_read(__func__); + +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + device->in_head_addr)); + tail = ioread16((void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + READ_FROM_DPRAM_VERIFY(&head, device->in_head_addr, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, device->in_tail_addr, sizeof(tail)); +#endif + +#ifdef PRINT_DPRAM_READ + LOGA("head: %d, tail: %d\n", head, tail); +#endif + + if (head != tail) + { + u16 up_tail = 0; + + // ------- tail ########## head -------- // + if (head > tail) + { + size = head - tail; + retval = dpram_tty_insert_data(device, (u8 *)(DPRAM_VBASE + (device->in_buff_addr + tail)), size); + if (size != retval) + LOGE("size: %d, retval: %d\n", size, retval); + } + // ####### head ------------ tail ###### // + else + { + int tmp_size = 0; + + // Total Size. + size = device->in_buff_size - tail + head; + + // 1. tail -> buffer end. + tmp_size = device->in_buff_size - tail; + retval = dpram_tty_insert_data(device, (u8 *)(DPRAM_VBASE + (device->in_buff_addr + tail)), tmp_size); + if (tmp_size != retval) + { + LOGE("size: %d, retval: %d\n", size, retval); + } + + // 2. buffer start -> head. + if (size > tmp_size) + { + retval_add = dpram_tty_insert_data(device, (u8 *)(DPRAM_VBASE + device->in_buff_addr), size - tmp_size); + retval += retval_add; + + if((size - tmp_size)!= retval_add) + { + LOGE("size - tmp_size: %d, retval_add: %d\n", size - tmp_size, retval_add); + } + } + } + + /* new tail */ + up_tail = (u16)((tail + retval) % device->in_buff_size); +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(up_tail, (void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->in_tail_addr, &up_tail, sizeof(up_tail)); +#endif + } + + + device->in_head_saved = head; + device->in_tail_saved = tail; + + dpram_unlock_read(__func__); + + if ( atomic_read(&fmt_txq_req_ack_rcvd) > 0 || (non_cmd & device->mask_req_ack) ) + { + // there is a situation where the q become full after we reached the tasklet. + // so this logic will allow us to send the RES_ACK as soon as we read 1 packet and CP get a chance to + // write another buffer. +// LOGA("Sending INT_MASK_RES_ACK_F\n"); + dpram_send_mbx_BA(INT_NON_COMMAND(device->mask_res_ack)); + atomic_set(&fmt_txq_req_ack_rcvd, 0); + } + + return retval; + +} + +static int dpram_read_raw(dpram_device_t *device, const u16 non_cmd) +{ + int retval = 0; + int size = 0; + u16 head, tail; + u16 up_tail = 0; + int ret; + size_t len; + struct pdp_info *dev = NULL; + struct pdp_hdr hdr; + u16 read_offset; + u8 len_high, len_low, id, control; + u16 pre_data_size; //pre_hdr_size, + u8 ch; + + dpram_lock_read(__func__); + +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + device->in_head_addr)); + tail = ioread16((void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + READ_FROM_DPRAM_VERIFY(&head, device->in_head_addr, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, device->in_tail_addr, sizeof(tail)); +#endif + +#ifdef PRINT_DPRAM_HEAD_TAIL + LOGA("head: %d, tail: %d\n", head, tail); +#endif + + if (head != tail) + { + up_tail = 0; + + if (head > tail) + /* ----- (tail) 7f 00 00 7e (head) ----- */ + size = head - tail; + else + /* 00 7e (head) ----------- (tail) 7f 00 */ + size = device->in_buff_size - tail + head; + + read_offset = 0; +#ifdef PRINT_DPRAM_HEAD_TAIL + LOGA("head: %d, tail: %d, size: %d\n", head, tail, size); +#endif + while (size) + { + READ_FROM_DPRAM(&ch, device->in_buff_addr +((u16)(tail + read_offset) % device->in_buff_size), sizeof(ch)); + + if (ch == 0x7F) + { + read_offset ++; + } + else + { + LOGE("First byte: 0x%02x, drop bytes: %d, buff addr: 0x%08lx, " + "read addr: 0x%08lx\n",ch, size, + (device->in_buff_addr), (device->in_buff_addr + + ((u16)(tail + read_offset) % device->in_buff_size))); + dpram_drop_data(device); + dpram_unlock_read(__func__); + return -1; + } + + len_high = len_low = id = control = 0; + READ_FROM_DPRAM(&len_low, device->in_buff_addr + ((u16)(tail + read_offset) % device->in_buff_size) ,sizeof(len_high)); + read_offset ++; + READ_FROM_DPRAM(&len_high, device->in_buff_addr + ((u16)(tail + read_offset) % device->in_buff_size) ,sizeof(len_low)); + read_offset ++; + READ_FROM_DPRAM(&id, device->in_buff_addr + ((u16)(tail + read_offset) % device->in_buff_size) ,sizeof(id)); + read_offset ++; + READ_FROM_DPRAM(&control, device->in_buff_addr + ((u16)(tail + read_offset) % device->in_buff_size) ,sizeof(control)); + read_offset ++; + + hdr.len = len_high <<8 | len_low; + hdr.id = id; + hdr.control = control; + + len = hdr.len - sizeof(struct pdp_hdr); + if (len <= 0) + { + LOGE("oops... read_offset: %d, len: %d, hdr.id: %d\n", read_offset, len, hdr.id); + dpram_drop_data(device); + dpram_unlock_read(__func__); + return -1; + } + + dev = pdp_get_dev(hdr.id); +#ifdef PRINT_DPRAM_READ + LOGA("read_offset: %d, len: %d, hdr.id: %d\n", read_offset, len, hdr.id); +#endif + if (!dev) + { + LOGE("RAW READ Failed.. NULL dev detected \n"); + check_pdp_table(__func__, __LINE__); + dpram_drop_data(device); + dpram_unlock_read(__func__); + return -1; + } + + if (dev->vs_dev.tty != NULL && dev->vs_dev.refcount) + { + if((u16)(tail + read_offset) % device->in_buff_size + len < device->in_buff_size) + { + ret = tty_insert_flip_string(dev->vs_dev.tty, (u8 *)(DPRAM_VBASE + (device->in_buff_addr + (u16)(tail + read_offset) % device->in_buff_size)), len); + dev->vs_dev.tty->low_latency = 0; + tty_flip_buffer_push(dev->vs_dev.tty); + } + else + { + pre_data_size = device->in_buff_size - (tail + read_offset); + ret = tty_insert_flip_string(dev->vs_dev.tty, (u8 *)(DPRAM_VBASE + (device->in_buff_addr + tail + read_offset)), pre_data_size); + ret += tty_insert_flip_string(dev->vs_dev.tty, (u8 *)(DPRAM_VBASE + (device->in_buff_addr)),len - pre_data_size); + dev->vs_dev.tty->low_latency = 0; + tty_flip_buffer_push(dev->vs_dev.tty); +#ifdef PRINT_DPRAM_READ + LOGE("RAW pre_data_size: %d, len-pre_data_size: %d, ret: %d\n", pre_data_size, len- pre_data_size, ret); +#endif + } + } + else + { + LOGE("tty channel(id:%d) is not opened!!!\n", dev->id); + ret = len; + } + + if (!ret) + { + LOGE("(tty_insert_flip_string) drop bytes: %d, " + "buff addr: 0x%08lx\n, read addr: 0x%08lx\n", + size, (device->in_buff_addr), + (device->in_buff_addr + ((u16)(tail + read_offset) + % device->in_buff_size))); + dpram_drop_data(device); + dpram_unlock_read(__func__); + return -1; + } + + read_offset += ret; +#ifdef PRINT_DPRAM_READ + LOGA("read_offset: %d, ret: %d\n", read_offset, ret); +#endif + READ_FROM_DPRAM(&ch, (device->in_buff_addr + ((u16)(tail + read_offset) % device->in_buff_size)), sizeof(ch)); + if (ch == 0x7e) + { + read_offset++; + } + else + { + LOGE("Last byte: 0x%02x, drop bytes: %d, buff addr: 0x%08lx, " + "read addr: 0x%08lx\n",ch, size, (device->in_buff_addr), + (device->in_buff_addr + ((u16)(tail + read_offset) % + device->in_buff_size))); + dpram_drop_data(device); + dpram_unlock_read(__func__); + return -1; + } + + size -= (ret + sizeof(struct pdp_hdr) + 2); + retval += (ret + sizeof(struct pdp_hdr) + 2); + + if (size < 0) + { + LOGE("something wrong....\n"); + break; + } + + } + + up_tail = (u16)((tail + read_offset) % device->in_buff_size); +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(up_tail, (void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->in_tail_addr, &up_tail, sizeof(up_tail)); +#endif + } + + device->in_head_saved = head; + device->in_tail_saved = tail; + + dpram_unlock_read(__func__); + + if ( atomic_read(&raw_txq_req_ack_rcvd) > 0 || (non_cmd & device->mask_req_ack) ) + { + // there is a situation where the q become full after we reached the tasklet. + // so this logic will allow us to send the RES_ACK as soon as we read 1 packet and CP get a chance to + // write another buffer. +// LOGA("Sending INT_MASK_RES_ACK_R\n"); + dpram_send_mbx_BA(INT_NON_COMMAND(device->mask_res_ack)); + atomic_set(&raw_txq_req_ack_rcvd, 0); + } + + return retval; +} + +static int dpram_init_magic_num(void) +{ + const u16 magic_code = 0x4D4E; + u16 acc_code = 0; + u16 ret_value = 0; + + PRINT_FUNC(); + + if ( dpram_lock_write(__func__) < 0 ) + return -EAGAIN; + + /*write DPRAM disable code */ + iowrite16(acc_code, (void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); + + /* write DPRAM magic code : Normal boot Magic - 0x4D4E*/ + iowrite16(magic_code, (void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + + /*write enable code */ + acc_code = 0x0001; + iowrite16(acc_code, (void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); + + /*send init end code to phone */ + dpram_unlock_write(__func__); + + ret_value = ioread16((void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + + LOGA("Read_MagicNum : 0x%04x\n", ret_value); + + return 0; + +} + + +#ifdef _ENABLE_ERROR_DEVICE +void request_phone_reset(void) +{ + return; + + /* char buf[DPRAM_ERR_MSG_LEN]; + unsigned long flags; + + dpram_init_magic_num(); + + memset((void *)buf, 0, sizeof (buf)); + + LOGE("CDMA reset cnt = %d\n", g_cp_reset_cnt); + if (g_cp_reset_cnt > 5) + { + buf[0] = '1'; + buf[1] = ' '; + memcpy(buf+2, "$CDMA-DEAD", sizeof("$CDMA-DEAD")); + } + else + { + buf[0] = '8'; + buf[1] = ' '; + memcpy(buf+2, "$PHONE-OFF", sizeof("$PHONE-OFF")); + } + + LOGE("[PHONE ERROR] ->> %s\n", buf); + local_irq_save(flags); + memcpy(dpram_err_buf, buf, DPRAM_ERR_MSG_LEN); + dpram_err_len = 64; + local_irq_restore(flags); + + wake_up_interruptible(&dpram_err_wait_q); + kill_fasync(&dpram_err_async_q, SIGIO, POLL_IN);*/ +} +#endif + + +static void dpram_send_mbx_BA(u16 irq_mask) +{ + if (g_dump_on) + return; + +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(irq_mask, (void *)dpram_mbx_BA); +#else + *dpram_mbx_BA = irq_mask; +#endif + +#ifdef PRINT_DPRAM_WRITE + LOG("mbx_BA = 0x%04X\n", irq_mask); +#endif +} + + +/* + * dpram_send_mbx_BA_cmd() + * - for prevent CP interrupt command miss issue, + * below function check the CP dpram interrupt level before send interrupt + */ +#define DPRAM_CMD_SEND_RETRY_CNT 0x5 +static void dpram_send_mbx_BA_cmd(u16 irq_mask) +{ + int retry_cnt = DPRAM_CMD_SEND_RETRY_CNT; + + if (g_dump_on) + return; + + /* Set GPIO_PDA_ACTIVE as CP sometimes seems to read this pin as Low */ + gpio_set_value(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + + while (gpio_get_value(GPIO_DPRAM_INT_CP_N) == 0 && retry_cnt--) + { + msleep(1); + LOGE("send cmd intr, retry cnt = %d\n", (DPRAM_CMD_SEND_RETRY_CNT-retry_cnt)); + + /* Set GPIO_PDA_ACTIVE as CP sometimes seems to read this pin as Low */ + LOGA("Current GPIO_PDA_ACTIVE = %d\n", gpio_get_value(GPIO_PDA_ACTIVE) ); + gpio_set_value(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + LOGA("GPIO_PDA_ACTIVE = %d\n", gpio_get_value(GPIO_PDA_ACTIVE) ); + } + +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(irq_mask, (void *)dpram_mbx_BA); +#else + *dpram_mbx_BA = irq_mask; +#endif + +#ifdef PRINT_DPRAM_WRITE + LOGA("mbx_BA = 0x%04X\n", irq_mask); +#endif +} + + +static void dpram_clear(void) +{ + long i = 0; + long size = 0; + unsigned long flags; + + u16 value = 0; + + size = DPRAM_SIZE - (DPRAM_INTERRUPT_PORT_SIZE * 4); + + /* @LDK@ clear DPRAM except interrupt area */ + local_irq_save(flags); + + for (i = DPRAM_PDA2PHONE_FORMATTED_HEAD_ADDRESS; i < size; i += 2) + { + iowrite16(0, (void *)(DPRAM_VBASE + i)); + } + + local_irq_restore(flags); + + value = ioread16((void *)dpram_mbx_AB); +} + +static int dpram_init_and_report(void) +{ + const u16 init_start = INT_COMMAND(MBX_CMD_INIT_START); + const u16 init_end = INT_COMMAND(MBX_CMD_INIT_END | AP_PLATFORM_ANDROID); + const u16 magic_code = 0x00AA; + u16 acc_code = 0; + +//#ifdef DEBUG_DPRAM_INT_HANDLER + PRINT_FUNC(); +//#endif + + dpram_send_mbx_BA(init_start); + + if ( dpram_lock_write(__func__) < 0 ) + return -EAGAIN; + + /* @LDK@ write DPRAM disable code */ + iowrite16(acc_code, (void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); + + /* @LDK@ dpram clear */ + dpram_clear(); + + /* @LDK@ write DPRAM magic code & enable code */ + iowrite16(magic_code, (void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + acc_code = 0x0001; + iowrite16(acc_code, (void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); + + /* @LDK@ send init end code to phone */ + dpram_unlock_write(__func__); + + dpram_send_mbx_BA(init_end); + +//#ifdef DEBUG_DPRAM_INT_HANDLER + LOGA("Sent CMD_INIT_END(0x%04X) to Phone!!!\n", init_end); +//#endif + + g_phone_sync = 1; + g_cp_reset_cnt = 0; + + return 0; +} + +static inline int dpram_get_read_available(dpram_device_t *device) +{ + u16 head = 0, tail = 0, size = 0; + +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + device->in_head_addr)); + tail = ioread16((void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + READ_FROM_DPRAM_VERIFY(&head, device->in_head_addr, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, device->in_tail_addr, sizeof(tail)); +#endif + + if ( tail >= device->in_buff_size || head >= device->in_buff_size ) + { + return 0; + } + + size = ( head >= tail )? (head - tail) : (device->in_buff_size - tail + head); + +#ifdef PRINT_DPRAM_READ + if ( size > 0 ) + LOGA("Data size = %d\n", size); +#endif + + return size; +} + +static void dpram_drop_data(dpram_device_t *device) +{ + u16 head, tail; + +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + device->in_head_addr)); + tail = ioread16((void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + READ_FROM_DPRAM_VERIFY(&head, device->in_head_addr, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, device->in_tail_addr, sizeof(tail)); +#endif + + if( head >= device->in_buff_size || tail >= device->in_buff_size ) + { + head = tail = 0 ; +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(head, (void *)(DPRAM_VBASE + device->in_head_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->in_head_addr, &head, sizeof(head)); +#endif + } + +#ifdef CDMA_IPC_C210_IDPRAM + iowrite16(head, (void *)(DPRAM_VBASE + device->in_tail_addr)); +#else + WRITE_TO_DPRAM_VERIFY(device->in_tail_addr, &head, sizeof(head)); +#endif + + LOGA("DROP head: %d, tail: %d\n", head, tail); +} + + +static void dpram_phone_power_on(void) +{ + u16 ret_value = 0; + + PRINT_FUNC(); + + /*Add for Gadui : Normal boot Magic - 0x54424D4E*/ + dpram_init_magic_num(); + + gpio_direction_output(GPIO_QSC_PHONE_RST, GPIO_LEVEL_HIGH); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + msleep(100); + + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_HIGH); + msleep(400); + msleep(400); + msleep(200); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + + + ret_value = ioread16((void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + LOGA("Read_MagicNum : 0x%04x\n", ret_value); + + +} + +static void dpram_only_qsc_phone_on_off(void) +{ + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + + LOGA("PHONE_ON level: %s\n", + gpio_get_value(GPIO_QSC_PHONE_ON) ? "HIGH" : "LOW "); +} + +static int dpram_phone_getstatus(void) +{ + return gpio_get_value(GPIO_QSC_PHONE_ACTIVE); +} + +static void dpram_phone_reset(void) +{ + PRINT_FUNC(); + + if(g_dpram_wpend == IDPRAM_WPEND_LOCK) + g_dpram_wpend = IDPRAM_WPEND_UNLOCK; // dpram write unlock + + /*Add for Gadui : Normal boot Magic - 0x54424D4E*/ + dpram_init_magic_num(); + + gpio_set_value(GPIO_QSC_PHONE_RST, GPIO_LEVEL_LOW); + msleep(100); + gpio_set_value(GPIO_QSC_PHONE_RST, GPIO_LEVEL_HIGH); + + g_cp_reset_cnt++; +} +static int dpram_extra_mem_rw(struct _param_em *param) +{ + + if(param->offset + param->size > 0xFFF800) + { + LOGE("Wrong rage of external memory access\n"); + return -1; + } + + if (param->rw) + { //write + if(dpram_lock_write(__func__) < 0) + return -EAGAIN; + WRITE_TO_DPRAM(param->offset, param->addr, param->size); + dpram_unlock_write(__func__); + } + else + { //read + dpram_lock_read(__func__); + READ_FROM_DPRAM(param->addr, param->offset, param->size); + dpram_unlock_read(__func__); + } + return 0; +} + +static int dpram_phone_ramdump_on(void) +{ + const u16 rdump_flag1 = 0xdead; + const u16 rdump_flag2 = 0xdead; + const u16 temp1, temp2; + + LOGL(DL_INFO,"Ramdump ON.\n"); + if(dpram_lock_write(__func__) < 0) + return -EAGAIN; + + WRITE_TO_DPRAM(DPRAM_MAGIC_CODE_ADDRESS, &rdump_flag1, sizeof(rdump_flag1)); + WRITE_TO_DPRAM(DPRAM_ACCESS_ENABLE_ADDRESS, &rdump_flag2, sizeof(rdump_flag2)); + + READ_FROM_DPRAM((void *)&temp1, DPRAM_MAGIC_CODE_ADDRESS, sizeof(temp1)); + READ_FROM_DPRAM((void *)&temp2, DPRAM_ACCESS_ENABLE_ADDRESS, sizeof(temp2)); + LOGL(DL_INFO,"flag1: %x flag2: %x\n", temp1, temp2); + + /* @LDK@ send init end code to phone */ + dpram_unlock_write(__func__); + + g_dump_on = 1; + // If it is configured to dump both AP and CP, reset both AP and CP here. + kernel_sec_dump_cp_handle2(); + + return 0; + +} + +static int dpram_phone_ramdump_off(void) +{ + const u16 rdump_flag1 = 0x00aa; + const u16 rdump_flag2 = 0x0001; + + LOGL(DL_INFO, "Ramdump OFF.\n"); + + g_dump_on = 0; + if(dpram_lock_write(__func__) < 0) + return -EAGAIN; + + WRITE_TO_DPRAM(DPRAM_MAGIC_CODE_ADDRESS, &rdump_flag1, sizeof(rdump_flag1)); + WRITE_TO_DPRAM(DPRAM_ACCESS_ENABLE_ADDRESS, &rdump_flag2, sizeof(rdump_flag2)); + /* @LDK@ send init end code to phone */ + dpram_unlock_write(__func__); + + //usb_switch_mode(1); #############Need to be enabled later + + g_phone_sync = 0; + + dpram_phone_reset(); + return 0; + +} + +#ifdef CONFIG_PROC_FS +static int dpram_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + int len; + + u16 magic, enable; + u16 fmt_in_head, fmt_in_tail, fmt_out_head, fmt_out_tail; + u16 raw_in_head, raw_in_tail, raw_out_head, raw_out_tail; + u16 in_interrupt = 0, out_interrupt = 0; + + int fih, fit, foh, fot; + int rih, rit, roh, rot; + +#ifdef _ENABLE_ERROR_DEVICE + char buf[DPRAM_ERR_MSG_LEN]; + unsigned long flags; +#endif /* _ENABLE_ERROR_DEVICE */ + + READ_FROM_DPRAM((void *)&magic, DPRAM_MAGIC_CODE_ADDRESS, sizeof(magic)); + READ_FROM_DPRAM((void *)&enable, DPRAM_ACCESS_ENABLE_ADDRESS, sizeof(enable)); + READ_FROM_DPRAM((void *)&fmt_in_head, DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS, sizeof(fmt_in_head)); + READ_FROM_DPRAM((void *)&fmt_in_tail, DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS, sizeof(fmt_in_tail)); + READ_FROM_DPRAM((void *)&fmt_out_head, DPRAM_PDA2PHONE_FORMATTED_HEAD_ADDRESS, sizeof(fmt_out_head)); + READ_FROM_DPRAM((void *)&fmt_out_tail, DPRAM_PDA2PHONE_FORMATTED_TAIL_ADDRESS, sizeof(fmt_out_tail)); + READ_FROM_DPRAM((void *)&raw_in_head, DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS, sizeof(raw_in_head)); + READ_FROM_DPRAM((void *)&raw_in_tail, DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS, sizeof(raw_in_tail)); + READ_FROM_DPRAM((void *)&raw_out_head, DPRAM_PDA2PHONE_RAW_HEAD_ADDRESS, sizeof(raw_out_head)); + READ_FROM_DPRAM((void *)&raw_out_tail, DPRAM_PDA2PHONE_RAW_TAIL_ADDRESS, sizeof(raw_out_tail)); + + fih = dpram_table[FORMATTED_INDEX].in_head_saved; + fit = dpram_table[FORMATTED_INDEX].in_tail_saved; + foh = dpram_table[FORMATTED_INDEX].out_head_saved; + fot = dpram_table[FORMATTED_INDEX].out_tail_saved; + rih = dpram_table[RAW_INDEX].in_head_saved; + rit = dpram_table[RAW_INDEX].in_tail_saved; + roh = dpram_table[RAW_INDEX].out_head_saved; + rot = dpram_table[RAW_INDEX].out_tail_saved; + out_interrupt = ioread16((void *)dpram_mbx_BA); + in_interrupt = ioread16((void *)dpram_mbx_AB); + +#ifdef _ENABLE_ERROR_DEVICE + memset((void *)buf, '\0', DPRAM_ERR_MSG_LEN); + local_irq_save(flags); + memcpy(buf, dpram_err_buf, DPRAM_ERR_MSG_LEN - 1); + local_irq_restore(flags); +#endif /* _ENABLE_ERROR_DEVICE */ + + p += sprintf(p, + "-------------------------------------\n" + "| NAME\t\t\t| VALUE\n" + "-------------------------------------\n" + "|R MAGIC CODE\t\t| 0x%04x\n" + "|R ENABLE CODE\t\t| 0x%04x\n" + "|R PHONE->PDA FMT HEAD\t| %u\n" + "|R PHONE->PDA FMT TAIL\t| %u\n" + "|R PDA->PHONE FMT HEAD\t| %u\n" + "|R PDA->PHONE FMT TAIL\t| %u\n" + "|R PHONE->PDA RAW HEAD\t| %u\n" + "|R RPHONE->PDA RAW TAIL\t| %u\n" + "|R PDA->PHONE RAW HEAD\t| %u\n" + "|R PDA->PHONE RAW TAIL\t| %u\n" + "-------------------------------------\n" + "| FMT PHONE->PDA HEAD\t| %d\n" + "| FMT PHONE->PDA TAIL\t| %d\n" + "| FMT PDA->PHONE HEAD\t| %d\n" + "| FMT PDA->PHONE TAIL\t| %d\n" + "-------------------------------------\n" + "| RAW PHONE->PDA HEAD\t| %d\n" + "| RAW PHONE->PDA TAIL\t| %d\n" + "| RAW PDA->PHONE HEAD\t| %d\n" + "| RAW PDA->PHONE TAIL\t| %d\n" + "-------------------------------------\n" + "| PHONE->PDA MAILBOX\t| 0x%04x\n" + "| PDA->PHONE MAILBOX\t| 0x%04x\n" + "-------------------------------------\n" +#ifdef _ENABLE_ERROR_DEVICE + "| LAST PHONE ERR MSG\t| %s\n" +#endif /* _ENABLE_ERROR_DEVICE */ + "| PHONE ACTIVE\t\t| %s\n" + "| DPRAM INT Level\t| %d\n" + "-------------------------------------\n", + magic, enable, + fmt_in_head, fmt_in_tail, fmt_out_head, fmt_out_tail, + raw_in_head, raw_in_tail, raw_out_head, raw_out_tail, + fih, fit, foh, fot, + rih, rit, roh, rot, + in_interrupt, out_interrupt, + +#ifdef _ENABLE_ERROR_DEVICE + (buf[0] != '\0' ? buf : "NONE"), +#endif /* _ENABLE_ERROR_DEVICE */ + (dpram_phone_getstatus() ? "ACTIVE" : "INACTIVE"), + gpio_get_value(IRQ_QSC_PHONE_ACTIVE) + ); + + len = (p - page) - off; + if (len < 0) { + len = 0; + } + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} +#endif /* CONFIG_PROC_FS */ + +/* dpram tty file operations. */ +static int dpram_tty_open(struct tty_struct *tty, struct file *file) +{ + dpram_device_t *device = &dpram_table[tty->index]; + + PRINT_FUNC(); + device->serial.tty = tty; + device->serial.open_count++; + + if (device->serial.open_count > 1) + { + device->serial.open_count--; + return -EBUSY; + } + + tty->driver_data = (void *)device; + tty->low_latency = 1; + return 0; +} + +static void dpram_tty_close(struct tty_struct *tty, struct file *file) +{ + dpram_device_t *device = (dpram_device_t *)tty->driver_data; + + //PRINT_FUNC(); + if ( device && (device == &dpram_table[tty->index]) ) + { + down(&device->serial.sem); + device->serial.open_count--; + device->serial.tty = NULL; + up(&device->serial.sem); + } +} + +static int dpram_tty_write(struct tty_struct *tty, const unsigned char *buffer, int count) +{ + dpram_device_t *device = (dpram_device_t *)tty->driver_data; + + //PRINT_FUNC(); + if (!device) + return 0; + + return dpram_write(device, buffer, count); +} + +static int dpram_tty_write_room(struct tty_struct *tty) +{ + int avail; + u16 head, tail; + dpram_device_t *device = (dpram_device_t *)tty->driver_data; + + //PRINT_FUNC(); + + if (device != NULL) + { + head = device->out_head_saved; + tail = device->out_tail_saved; + + avail = (head < tail) ? (tail - head - 1) : (device->out_buff_size + tail - head - 1); + + return avail; + } + + return 0; +} + +static int dpram_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) +{ + unsigned int val; + + PRINT_FUNC(); + switch (cmd) + { + case DPRAM_PHONE_ON: + g_phone_sync = 0; + g_dump_on = 0; + g_phone_power_off_sequence = 0; + LOGA("IOCTL cmd = DPRAM_PHONE_ON\n"); + dpram_phone_power_on(); + return 0; + + case DPRAM_PHONE_GETSTATUS: + LOGA("IOCTL cmd = DPRAM_PHONE_GETSTATUS\n"); + val = dpram_phone_getstatus(); + return copy_to_user((unsigned int *)arg, &val, sizeof(val)); + + case DPRAM_PHONE_RESET: + g_phone_sync = 0; + g_dump_on = 0; + g_phone_power_off_sequence = 0; + LOGA("IOCTL cmd = DPRAM_PHONE_RESET\n"); + dpram_phone_reset(); + return 0; + + case DPRAM_PHONE_OFF: + g_phone_sync = 0; + g_phone_power_off_sequence = 1; + LOGA("IOCTL cmd = DPRAM_PHONE_OFF\n"); + dpram_only_qsc_phone_on_off(); + return 0; + + // Silent reset + case MBX_CMD_PHONE_RESET: + LOGA("IOCTL cmd = MBX_CMD_PHONE_RESET\n"); + request_phone_reset(); + return 0; + + case DPRAM_PHONE_RAMDUMP_ON: + LOGA("IOCTL cmd = DPRAM_PHONE_RAMDUMP_ON\n"); + dpram_phone_ramdump_on(); + return 0; + + case DPRAM_PHONE_RAMDUMP_OFF: + LOGA("IOCTL cmd = DPRAM_PHONE_RAMDUMP_OFF\n"); + dpram_phone_ramdump_off(); + return 0; + + case DPRAM_PHONE_UNSET_UPLOAD: + LOGA("IOCTL cmd = DPRAM_PHONE_UNSET_UPLOAD\n"); +#ifdef CONFIG_SEC_DEBUG + kernel_sec_clear_upload_magic_number(); +#endif + break; + + case DPRAM_PHONE_SET_AUTOTEST: + LOGA("IOCTL cmd = DPRAM_PHONE_SET_AUTOTEST\n"); +#ifdef CONFIG_SEC_DEBUG + kernel_sec_set_autotest(); +#endif + break; + + case DPRAM_PHONE_GET_DEBUGLEVEL: + LOGA("IOCTL cmd = DPRAM_PHONE_GET_DEBUGLEVEL\n"); +#ifdef CONFIG_SEC_DEBUG + switch(kernel_sec_get_debug_level()) { + case KERNEL_SEC_DEBUG_LEVEL_LOW: + val = 0xA0A0; + break; + case KERNEL_SEC_DEBUG_LEVEL_MID: + val = 0xB0B0; + break; + case KERNEL_SEC_DEBUG_LEVEL_HIGH: + val = 0xC0C0; + break; + default: + val = 0xFFFF; + break; + } + LOGA("DPRAM_PHONE_GET_DEBUGLEVEL = %x, %d\n", kernel_sec_get_debug_level(), val); +#endif + return copy_to_user((unsigned int *)arg, &val, sizeof(val)); + + break; + + case DPRAM_PHONE_SET_DEBUGLEVEL: + LOGA("IOCTL cmd = DPRAM_PHONE_SET_DEBUGLEVEL\n"); +#ifdef CONFIG_SEC_DEBUG + switch(kernel_sec_get_debug_level()) { + case KERNEL_SEC_DEBUG_LEVEL_LOW: + kernel_sec_set_debug_level(KERNEL_SEC_DEBUG_LEVEL_MID); + break; + case KERNEL_SEC_DEBUG_LEVEL_MID: + kernel_sec_set_debug_level(KERNEL_SEC_DEBUG_LEVEL_HIGH); + break; + case KERNEL_SEC_DEBUG_LEVEL_HIGH: + kernel_sec_set_debug_level(KERNEL_SEC_DEBUG_LEVEL_LOW); + break; + default: + break; + } +#endif + return 0; + + case DPRAM_EXTRA_MEM_RW: + { + struct _param_em param; + + LOGA("IOCTL cmd = DPRAM_EXTRA_MEM_RW\n"); + + val = copy_from_user((void *)¶m, (void *)arg, sizeof(param)); + if (dpram_extra_mem_rw(¶m) < 0) + { + LOGE("External memory access fail..\n"); + return -1; + } + + if (!param.rw) //read + { + return copy_to_user((unsigned long *)arg, ¶m, sizeof(param)); + } + + return 0; + } + + case DPRAM_PHONE_CPRAMDUMP_START: + { + LOGA("IOCTL cmd = DPRAM_PHONE_CPRAMDUMP_START\n"); +// setup_cp_ramdump(); +// LOGA("Succeeded in setup_cp_ramdump()!!!\n"); + return 0; + } + + case DPRAM_PHONE_CPRAMDUMP_DONE: + { + int ret; + + LOGA("IOCTL cmd = DPRAM_PHONE_CPRAMDUMP_DONE\n"); + + dpram_send_command(CMD_CP_RAMDUMP_SEND_DONE_REQ); + ret = dpram_wait_response(CMD_CP_RAMDUMP_SEND_DONE_RESP|MASK_CMD_RESULT_SUCCESS); + if (!ret) { + LOGE("Failed in dpram_wait_response()!!!\n"); + return 0; + } + LOGE("succeeded in dpram_wait_response()!!!\n"); + dpram_clear_response(); + + // goto Upload mode +#ifdef CONFIG_SEC_DEBUG + if (kernel_sec_get_debug_level() != KERNEL_SEC_DEBUG_LEVEL_LOW) { + LOGE("Upload Mode!!!\n"); + kernel_sec_dump_cp_handle2(); + } +#endif + + return 0; + } + + default: + LOGA("IOCTL cmd = 0x%X\n", cmd); + break; + } + + return -ENOIOCTLCMD; +} + +static int dpram_tty_chars_in_buffer(struct tty_struct *tty) +{ + int data; + u16 head, tail; + + + dpram_device_t *device = (dpram_device_t *)tty->driver_data; + + //PRINT_FUNC(); + if (device != NULL) + { + head = device->out_head_saved; + tail = device->out_tail_saved; + + data = (head > tail) ? (head - tail - 1) : (device->out_buff_size - tail + head); + + return data; + } + + return 0; +} + +#ifdef _ENABLE_ERROR_DEVICE +static int dpram_err_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + + ssize_t ret; + size_t ncopy; + + //PRINT_FUNC(); + add_wait_queue(&dpram_err_wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (1) { + if (dpram_err_len) { + ncopy = min(count, dpram_err_len); + if (copy_to_user(buf, dpram_err_buf, ncopy)) + ret = -EFAULT; + else + ret = ncopy; + + dpram_err_len = 0; + + break; + } + + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&dpram_err_wait_q, &wait); + + return ret; +} + +static int dpram_err_fasync(int fd, struct file *filp, int mode) +{ + //PRINT_FUNC(); + return fasync_helper(fd, filp, mode, &dpram_err_async_q); +} + +static unsigned int dpram_err_poll(struct file *filp, + struct poll_table_struct *wait) +{ + poll_wait(filp, &dpram_err_wait_q, wait); + return ((dpram_err_len) ? (POLLIN | POLLRDNORM) : 0); +} + +static int dpram_dump_open(struct inode *inode, struct file *filp) +{ + struct cdev *cdev = inode->i_cdev; + struct dpram *dp = container_of(cdev, struct dpram, cdev); + + //PRINT_FUNC(); + LOGA("Invoked!!!\n"); + filp->private_data = dp; + + setup_cp_ramdump(); + + return 0; +} + +static int dpram_dump_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +{ + int ret; + int ncopy; + + //PRINT_FUNC(); + receive_cp_ramdump(); + + ncopy = min(count, dpram_dump_len); + if (copy_to_user(buf, cp_ramdump_buff, ncopy)) + ret = -EFAULT; + else + ret = ncopy; + + dpram_dump_len = 0; + + LOGA("RX bytes = %d\n", dump_rx_total); + + return ret; +} + +static int dpram_dump_fasync(int fd, struct file *filp, int mode) +{ + return fasync_helper(fd, filp, mode, &dpram_dump_async_q); +} + +static unsigned int dpram_dump_poll(struct file *filp, + struct poll_table_struct *wait) +{ + LOGA("%d bytes are ready.\n", dpram_dump_len); + poll_wait(filp, &dpram_dump_wait_q, wait); + return ((dpram_dump_len) ? (POLLIN | POLLRDNORM) : 0); +} + +static long dpram_dump_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) + { + case DPRAM_PHONE_CPRAMDUMP_START: + { + LOGA("IOCTL cmd = DPRAM_PHONE_CPRAMDUMP_START\n"); + + start_cp_ramdump(); + return 0; + } + + case DPRAM_PHONE_CPRAMDUMP_DONE: + { + LOGA("IOCTL cmd = DPRAM_PHONE_CPRAMDUMP_DONE\n"); + + close_cp_ramdump(); + +#ifdef CONFIG_SEC_DEBUG + /* Go to Upload mode*/ + if (kernel_sec_get_debug_level() != KERNEL_SEC_DEBUG_LEVEL_LOW) + kernel_sec_dump_cp_handle2(); +#endif + + return 0; + } + + default: + LOGA("IOCTL cmd = 0x%X\n", cmd); + break; + } + + return -ENOIOCTLCMD; +} + + +#endif /* _ENABLE_ERROR_DEVICE */ + +/* handlers. */ +static void res_ack_tasklet_handler(unsigned long data) +{ + dpram_device_t *device = (dpram_device_t *)data; + + //PRINT_FUNC(); + if (device && device->serial.tty) { + struct tty_struct *tty = device->serial.tty; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc->ops->write_wakeup) { + (tty->ldisc->ops->write_wakeup)(tty); + } + + wake_up_interruptible(&tty->write_wait); + } +} + +static void fmt_rcv_tasklet_handler(unsigned long data) +{ + dpram_tasklet_data_t *tasklet_data = (dpram_tasklet_data_t *)data; + + dpram_device_t *device = tasklet_data->device; + u16 non_cmd = tasklet_data->non_cmd; + + int ret = 0; + int cnt = 0; + + //PRINT_FUNC(); + if (device && device->serial.tty) + { + struct tty_struct *tty = device->serial.tty; + + while (dpram_get_read_available(device)) + { + ret = dpram_read_fmt(device, non_cmd); + + if (!ret) + cnt++; + + if (cnt > 10) + { + dpram_drop_data(device); + break; + } + + if (ret < 0) + { + LOGE("FMT dpram_read_fmt failed\n"); + /* TODO: ... wrong.. */ + } + tty->low_latency = 0; + tty_flip_buffer_push(tty); + } + } + else + { + dpram_drop_data(device); + } +} + +static void raw_rcv_tasklet_handler(unsigned long data) +{ + dpram_tasklet_data_t *tasklet_data = (dpram_tasklet_data_t *)data; + + dpram_device_t *device = tasklet_data->device; + u16 non_cmd = tasklet_data->non_cmd; + + int ret = 0; + //PRINT_FUNC(); + while (dpram_get_read_available(device)) + { + ret = dpram_read_raw(device, non_cmd); + + if (ret < 0) + { + LOGE("RAW dpram_read_raw failed\n"); + /* TODO: ... wrong.. */ + } + } +} + +static void cmd_req_active_handler(void) +{ + dpram_send_mbx_BA(INT_COMMAND(MBX_CMD_RES_ACTIVE)); +} + +/* static void cmd_error_display_handler(void) + * + * this fucntion was called by dpram irq handler and phone active irq hander + * first this fucntion check the log level then jump to send error message to ril + * or CP Upload mode + */ +static void cmd_error_display_handler(void) +{ +#ifdef _ENABLE_ERROR_DEVICE + unsigned short intr; + unsigned long flags; + char buf[DPRAM_ERR_MSG_LEN]; + + memset((void *)buf, 0, sizeof (buf)); + +#ifdef CONFIG_SEC_DEBUG + if (dpram_err_cause == UPLOAD_CAUSE_CDMA_RESET) { + if(get_sec_debug_level()) + memcpy((void *)buf, "UPLOAD", sizeof("UPLOAD")); + else /*debug level is low*/ + memcpy((void *)buf, "9 $PHONE-RESET", sizeof("9 $PHONE-RESET")); + } + else { + if(get_sec_debug_level()) { + buf[0] = 'C'; + buf[1] = 'D'; + buf[2] = 'M'; + buf[3] = 'A'; + buf[4] = ' '; + READ_FROM_DPRAM((buf + 5), DPRAM_PHONE2PDA_FORMATTED_BUFFER_ADDRESS, (sizeof(buf) - 6)); + } else /*debug level is low */ + memcpy((void *)buf, "9 $PHONE-RESET", sizeof("9 $PHONE-RESET")); + } + LOGE("[PHONE ERROR] ->> %s\n", buf); + memcpy(dpram_err_buf, buf, DPRAM_ERR_MSG_LEN); + dpram_err_len = 64; + LOGE("start wake_lock_timeout: during 20sec\n"); + wake_lock_timeout(&dpram_wake_lock, HZ*20); + /* goto Upload mode : receive C9 */ + if ((get_sec_debug_level())&& \ + (dpram_err_cause != UPLOAD_CAUSE_CDMA_RESET)) + /*if (sec_debug_level())*/ + { + local_irq_save(flags); + LOGE("Upload Mode!!!\n"); + intr = ioread16((void *)dpram_mbx_AB); + if (intr == (MBX_CMD_CDMA_DEAD|INT_MASK_VALID|INT_MASK_COMMAND)) + { + LOGE("mbx_AB = 0x%04X\n", intr); + } + kernel_sec_dump_cp_handle2(); + local_irq_restore(flags); + } + dpram_err_cause = 0; + wake_up_interruptible(&dpram_err_wait_q); + kill_fasync(&dpram_err_async_q, SIGIO, POLL_IN); +#endif +#endif /* _ENABLE_ERROR_DEVICE */ +} + + +static void cmd_phone_start_handler(void) +{ + LOGA("Received CMD_PHONE_START!!! %d\n", g_phone_sync); + + PRINT_FUNC(); + if (g_phone_sync == 0) { + /* Set GPIO_PDA_ACTIVE as CP sometimes seems to read this pin as Low */ + LOGA("Current GPIO_PDA_ACTIVE = %d\n", gpio_get_value(GPIO_PDA_ACTIVE) ); + gpio_set_value(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + + dpram_init_and_report(); + + LOGA("GPIO_PDA_ACTIVE = %d\n", gpio_get_value(GPIO_PDA_ACTIVE) ); + } +} + + +static void cmd_req_time_sync_handler(void) +{ + /* TODO: add your codes here.. */ +} + +static void cmd_phone_deep_sleep_handler(void) +{ + /* TODO: add your codes here.. */ +} + +static void dpram_command_handler(u16 cmd) +{ +//PRINT_FUNC(); + switch (cmd) + { + case MBX_CMD_REQ_ACTIVE: + cmd_req_active_handler(); + break; + + case MBX_CMD_CDMA_DEAD: + LOGE("received MBX_CMD_CDMA_DEAD\n"); + cmd_error_display_handler(); + break; + + case MBX_CMD_ERR_DISPLAY: + LOGE("received MBX_CMD_ERR_DISPLAY\n"); + cmd_error_display_handler(); + break; + + case MBX_CMD_PHONE_START: + cmd_phone_start_handler(); + break; + + case MBX_CMD_REQ_TIME_SYNC: + cmd_req_time_sync_handler(); + break; + + case MBX_CMD_PHONE_DEEP_SLEEP: + cmd_phone_deep_sleep_handler(); + break; + + case MBX_CMD_DPRAM_DOWN: + dpram_power_down(); + break; + + case MBX_CMD_CP_WAKEUP_START: + dpram_powerup_start(); + break; + + default: + LOGA("Unknown command (0x%04X)\n", cmd); + } +} + +static void dpram_data_handler(u16 non_cmd) +{ + u16 head, tail; + + // PRINT_FUNC(); + /* @LDK@ formatted check. */ +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS)); + tail = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS)); +#else + READ_FROM_DPRAM_VERIFY(&head, DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS, sizeof(tail)); +#endif + + if (head != tail) + { + non_cmd |= INT_MASK_SEND_F; + + if (non_cmd & INT_MASK_REQ_ACK_F) + atomic_inc(&fmt_txq_req_ack_rcvd); + } + else + { + if (non_cmd & INT_MASK_REQ_ACK_F) + { + LOGA("FMT DATA EMPTY & REQ_ACK_F (non_cmd:0x%x)\n", non_cmd); + dpram_send_mbx_BA(INT_NON_COMMAND(INT_MASK_RES_ACK_F)); + atomic_set(&fmt_txq_req_ack_rcvd, 0); + } + } + + /* @LDK@ raw check. */ +#ifdef CDMA_IPC_C210_IDPRAM + head = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS)); + tail = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS)); +#else + READ_FROM_DPRAM_VERIFY(&head, DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS, sizeof(head)); + READ_FROM_DPRAM_VERIFY(&tail, DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS, sizeof(tail)); +#endif + + if (head != tail) + { + non_cmd |= INT_MASK_SEND_R; + + if (non_cmd & INT_MASK_REQ_ACK_R) + atomic_inc(&raw_txq_req_ack_rcvd); + } + else + { + if (non_cmd & INT_MASK_REQ_ACK_R) + { + LOGA("RAW DATA EMPTY & REQ_ACK_R (non_cmd:0x%x)\n", non_cmd); + dpram_send_mbx_BA(INT_NON_COMMAND(INT_MASK_RES_ACK_R)); + atomic_set(&raw_txq_req_ack_rcvd, 0); + } + } + + /* @LDK@ +++ scheduling.. +++ */ + if (non_cmd & INT_MASK_SEND_F) + { + dpram_tasklet_data[FORMATTED_INDEX].device = &dpram_table[FORMATTED_INDEX]; + dpram_tasklet_data[FORMATTED_INDEX].non_cmd = non_cmd; + fmt_send_tasklet.data = (unsigned long)&dpram_tasklet_data[FORMATTED_INDEX]; + tasklet_schedule(&fmt_send_tasklet); + } + + if (non_cmd & INT_MASK_SEND_R) + { + dpram_tasklet_data[RAW_INDEX].device = &dpram_table[RAW_INDEX]; + dpram_tasklet_data[RAW_INDEX].non_cmd = non_cmd; + raw_send_tasklet.data = (unsigned long)&dpram_tasklet_data[RAW_INDEX]; + /* @LDK@ raw buffer op. -> soft irq level. */ + tasklet_hi_schedule(&raw_send_tasklet); + } + + if (non_cmd & INT_MASK_RES_ACK_F) + { + tasklet_schedule(&fmt_res_ack_tasklet); + } + + if (non_cmd & INT_MASK_RES_ACK_R) + { + tasklet_hi_schedule(&raw_res_ack_tasklet); + } +} + +static inline void check_int_pin_level(void) +{ + u16 mask = 0, cnt = 0; + + while (cnt++ < 3) + { + mask = ioread16((void *)dpram_mbx_AB); + if ( gpio_get_value(GPIO_DPRAM_INT_CP_N) ) + break; + } +} + +static void phone_active_work_func(struct work_struct *work) +{ + u32 reset_code; + + //PRINT_FUNC(); + LOGA("PHONE_ACTIVE level: %s, phone_sync: %d\n", + gpio_get_value(GPIO_QSC_PHONE_ACTIVE) ? "HIGH" : "LOW ", + g_phone_sync); + +#ifdef _ENABLE_ERROR_DEVICE + /* + ** If CDMA was reset by watchdog, phone active low time is very short. So, + ** change the IRQ type to FALLING EDGE and don't check the GPIO_QSC_PHONE_ACTIVE. + */ + if (g_phone_sync) { +#ifdef DUMP_OF_PHONE_ACTIVE_LOW_CRASH + free_irq(dpram_irq, NULL); + IDPRAM_INT_CLEAR(); + free_irq(phone_active_irq, NULL); + g_dump_on = 1; + init_completion(&wait_dump_data); +#endif + memcpy_fromio(&reset_code, (void *)DPRAM_VBASE, sizeof(reset_code)); + if (reset_code != CP_RESET_CODE) { +#ifdef CONFIG_SEC_DEBUG + dpram_err_cause = UPLOAD_CAUSE_CDMA_RESET; +#endif + if (g_phone_power_off_sequence != 1) + cmd_error_display_handler(); + } + } +#endif +} + + +/* @LDK@ interrupt handlers. */ +static irqreturn_t dpram_irq_handler(int irq, void *dev_id) +{ + unsigned long flags; + u16 irq_mask = 0; +#ifdef PRINT_DPRAM_HEAD_TAIL + u16 fih, fit, foh, fot; + u16 rih, rit, roh, rot; +#endif + + //PRINT_FUNC(); + local_irq_save(flags); + local_irq_disable(); + + irq_mask = ioread16((void *)dpram_mbx_AB); + //check_int_pin_level(); + + if (g_dump_on) { + g_irq_mask = irq_mask; + IDPRAM_INT_CLEAR(); + complete(&wait_dump_data); + LOGA("g_dump_on == 1\n"); + local_irq_restore(flags); + return IRQ_HANDLED; + } + +#ifdef DEBUG_DPRAM_INT_HANDLER + LOGA("INT2AP: 0x%04X\n", irq_mask); +#endif + + /* valid bit verification. @LDK@ */ + if ( !(irq_mask & INT_MASK_VALID) ) + { + LOGE("Invalid interrupt mask: 0x%04x\n", irq_mask); + IDPRAM_INT_CLEAR(); + local_irq_restore(flags); + return IRQ_NONE; + } + + /* command or non-command? @LDK@ */ + if ( irq_mask & INT_MASK_COMMAND ) + { + irq_mask &= ~(INT_MASK_VALID | INT_MASK_COMMAND); + dpram_command_handler(irq_mask); + } + else + { +#ifdef PRINT_DPRAM_HEAD_TAIL + fih = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS)); + fit = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS)); + foh = ioread16((void *)(DPRAM_VBASE + DPRAM_PDA2PHONE_FORMATTED_HEAD_ADDRESS)); + fot = ioread16((void *)(DPRAM_VBASE + DPRAM_PDA2PHONE_FORMATTED_TAIL_ADDRESS)); + rih = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS)); + rit = ioread16((void *)(DPRAM_VBASE + DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS)); + roh = ioread16((void *)(DPRAM_VBASE + DPRAM_PDA2PHONE_RAW_HEAD_ADDRESS)); + rot = ioread16((void *)(DPRAM_VBASE + DPRAM_PDA2PHONE_RAW_TAIL_ADDRESS)); + LOGA(" FMT_IN (H:%4d, T:%4d, M:%4d)\n FMT_OUT (H:%4d, T:%4d, M:%4d)\n RAW_IN (H:%4d, T:%4d, M:%4d)\n RAW_OUT (H:%4d, T:%4d, M:%4d)\n", + fih, fit, DPRAM_PHONE2PDA_FORMATTED_BUFFER_SIZE, + foh, fot, DPRAM_PDA2PHONE_FORMATTED_BUFFER_SIZE, + rih, rit, DPRAM_PHONE2PDA_RAW_BUFFER_SIZE, + roh, rot, DPRAM_PDA2PHONE_RAW_BUFFER_SIZE); +#endif + irq_mask &= ~INT_MASK_VALID; + dpram_data_handler(irq_mask); + } + + IDPRAM_INT_CLEAR(); + + local_irq_restore(flags); + return IRQ_HANDLED; +} + + +static irqreturn_t dpram_wake_from_CP_irq_handler(int irq, void *dev_id) +{ +#ifdef DEBUG_DPRAM_INT_HANDLER + LOGA("wake_lock_timeout() in 5 seconds.\n", __func__); +#endif + + wake_lock_timeout(&dpram_wake_lock, 5*HZ); + + return IRQ_HANDLED; +} + +static irqreturn_t phone_active_irq_handler(int irq, void *dev_id) +{ + schedule_delayed_work(&phone_active_work, msecs_to_jiffies(1)); + return IRQ_HANDLED; +} + +static irqreturn_t cp_dump_irq_handler(int irq, void *dev_id) +{ + //only print log + //LOGA("CP_DUMP_INT - High\n", __func__); + return IRQ_HANDLED; +} + + +static int kernel_sec_dump_cp_handle2(void) +{ +#ifdef CONFIG_SEC_DEBUG + LOGA("Configure to restart AP and collect dump on restart...\n"); + /* output high */ + gpio_set_value(S5PV310_GPE0_3_MDM_IRQn, GPIO_LEVEL_HIGH); + /* GPIO output mux */ + s3c_gpio_cfgpin(S5PV310_GPE0_0_MDM_WEn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_1_MDM_CSn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_2_MDM_Rn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_3_MDM_IRQn, S3C_GPIO_SFN(S3C_GPIO_OUTPUT)); + s3c_gpio_cfgpin(S5PV310_GPE0_4_MDM_ADVN, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + if (dpram_err_len) + kernel_sec_set_cause_strptr(dpram_err_buf, dpram_err_len); + panic("CP Crash"); +#endif + return 0; +} + +/* basic functions. */ +#ifdef _ENABLE_ERROR_DEVICE +static struct file_operations dpram_err_ops = { + .owner = THIS_MODULE, + .read = dpram_err_read, + .fasync = dpram_err_fasync, + .poll = dpram_err_poll, + .llseek = no_llseek, + + /* TODO: add more operations */ +}; + +static struct file_operations dpram_dump_ops = { + .owner = THIS_MODULE, + .open = dpram_dump_open, + .read = dpram_dump_read, + .fasync = dpram_dump_fasync, + .poll = dpram_dump_poll, + .unlocked_ioctl = dpram_dump_ioctl, + .llseek = no_llseek, +}; +#endif /* _ENABLE_ERROR_DEVICE */ + +static struct tty_operations dpram_tty_ops = { + .open = dpram_tty_open, + .close = dpram_tty_close, + .write = dpram_tty_write, + .write_room = dpram_tty_write_room, + .ioctl = dpram_tty_ioctl, + .chars_in_buffer = dpram_tty_chars_in_buffer, + + /* TODO: add more operations */ +}; + +#ifdef _ENABLE_ERROR_DEVICE +static void unregister_dpram_err_device(void) +{ + unregister_chrdev(DRIVER_MAJOR_NUM, DPRAM_ERR_DEVICE); + class_destroy(dpram_err_class); +} + +static int register_dpram_err_device(void) +{ + struct device *dpram_err_dev_t; + int ret; + + ret = register_chrdev(DRIVER_MAJOR_NUM, DPRAM_ERR_DEVICE, &dpram_err_ops); + if (ret < 0) + return ret; + + dpram_err_class = class_create(THIS_MODULE, "err"); + if (IS_ERR(dpram_err_class)) { + unregister_dpram_err_device(); + return -EFAULT; + } + + /* @LDK@ 1 = formatted, 2 = raw, so error device is '0' */ + dpram_err_dev_t = device_create( + dpram_err_class, + NULL, + MKDEV(DRIVER_MAJOR_NUM, 0), + NULL, + DPRAM_ERR_DEVICE); + if (IS_ERR(dpram_err_dev_t)) { + unregister_dpram_err_device(); + return -EFAULT; + } + + return 0; +} + +static void unregister_dpram_dump_device(void) +{ + unregister_chrdev(DPRAM_DUMP_DEV_MAJOR, DPRAM_DUMP_DEVICE); + class_destroy(dpram_dump_class); +} + +static int register_dpram_dump_device(void) +{ + struct device *dpram_dump_dev_t; + int ret; + + ret = register_chrdev(DPRAM_DUMP_DEV_MAJOR, DPRAM_DUMP_DEVICE, &dpram_dump_ops); + if (ret < 0) + { + LOGE("Failed in register_chrdev() (%d)\n", ret); + return ret; + } + + dpram_dump_class = class_create(THIS_MODULE, "dump"); + if (IS_ERR(dpram_dump_class)) { + LOGE("Failed in class_create()\n"); + unregister_dpram_dump_device(); + return -EFAULT; + } + + dpram_dump_dev_t = device_create( + dpram_dump_class, + NULL, + MKDEV(DPRAM_DUMP_DEV_MAJOR, 0), + NULL, + DPRAM_DUMP_DEVICE); + if (IS_ERR(dpram_dump_dev_t)) { + LOGE("Failed in device_create()\n"); + unregister_dpram_dump_device(); + return -EFAULT; + } + + return 0; +} +#endif /* _ENABLE_ERROR_DEVICE */ + +static int register_dpram_driver(void) +{ + int retval = 0; + + /* @LDK@ allocate tty driver */ + dpram_tty_driver = alloc_tty_driver(MAX_INDEX); + + if (!dpram_tty_driver) { + return -ENOMEM; + } + + /* @LDK@ initialize tty driver */ + dpram_tty_driver->owner = THIS_MODULE; + dpram_tty_driver->magic = TTY_DRIVER_MAGIC; + dpram_tty_driver->driver_name = DRIVER_NAME; + dpram_tty_driver->name = "dpram"; + dpram_tty_driver->major = DRIVER_MAJOR_NUM; + dpram_tty_driver->minor_start = 1; + dpram_tty_driver->num = MAX_INDEX; + dpram_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + dpram_tty_driver->subtype = SERIAL_TYPE_NORMAL; + dpram_tty_driver->flags = TTY_DRIVER_REAL_RAW; + dpram_tty_driver->init_termios = tty_std_termios; + dpram_tty_driver->init_termios.c_cflag = (B115200 | CS8 | CREAD | CLOCAL | HUPCL); + tty_set_operations(dpram_tty_driver, &dpram_tty_ops); + + dpram_tty_driver->ttys = dpram_tty; + dpram_tty_driver->termios = dpram_termios; + dpram_tty_driver->termios_locked = dpram_termios_locked; + + /* @LDK@ register tty driver */ + retval = tty_register_driver(dpram_tty_driver); + if (retval) { + LOGE("tty_register_driver error\n"); + put_tty_driver(dpram_tty_driver); + return retval; + } + + return 0; +} + +static void unregister_dpram_driver(void) +{ + tty_unregister_driver(dpram_tty_driver); +} + +/* + * MULTI PDP FUNCTIONs + */ + +static long multipdp_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -EINVAL; +} + +static struct file_operations multipdp_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = multipdp_ioctl, + .llseek = no_llseek, +}; + +static struct miscdevice multipdp_dev = { + .minor = 132, //MISC_DYNAMIC_MINOR, + .name = APP_DEVNAME, + .fops = &multipdp_fops, +}; + +static inline struct pdp_info * pdp_get_serdev(const char *name) +{ + int slot; + struct pdp_info *dev; + + for (slot = 0; slot < MAX_PDP_CONTEXT; slot++) { + dev = pdp_table[slot]; + if (dev && dev->type == DEV_TYPE_SERIAL && + strcmp(name, dev->vs_dev.tty_name) == 0) { + return dev; + } + } + return NULL; +} + +static inline struct pdp_info * pdp_remove_dev(u8 id) +{ + int slot; + struct pdp_info *dev; + + for (slot = 0; slot < MAX_PDP_CONTEXT; slot++) { + if (pdp_table[slot] && pdp_table[slot]->id == id) { + dev = pdp_table[slot]; + pdp_table[slot] = NULL; + return dev; + } + } + return NULL; +} + +static int vs_open(struct tty_struct *tty, struct file *filp) +{ + struct pdp_info *dev; + //PRINT_FUNC(); + dev = pdp_get_serdev(tty->driver->name); // 2.6 kernel porting + + if (dev == NULL) { + return -ENODEV; + } + + tty->driver_data = (void *)dev; + tty->low_latency = 1; + dev->vs_dev.tty = tty; + dev->vs_dev.refcount++; + + return 0; +} + +static void vs_close(struct tty_struct *tty, struct file *filp) +{ + struct pdp_info *dev; + + dev = pdp_get_serdev(tty->driver->name); + + if (!dev ) + return; + dev->vs_dev.refcount--; + + return; +} + +static int pdp_mux(struct pdp_info *dev, const void *data, size_t len ) +{ + int ret; + size_t nbytes; + u8 *tx_buf; + struct pdp_hdr *hdr; + const u8 *buf; + + int in_softirq_context = in_softirq(); + + /* check current context */ + if (in_softirq_context) + spin_lock(&mux_tty_lock); + else + spin_lock_bh(&mux_tty_lock); + + tx_buf = dev->tx_buf; + hdr = (struct pdp_hdr *)(tx_buf + 1); + buf = data; + + hdr->id = dev->id; + hdr->control = 0; + + while (len) { + if (len > MAX_PDP_DATA_LEN) { + nbytes = MAX_PDP_DATA_LEN; + } else { + nbytes = len; + } + hdr->len = nbytes + sizeof(struct pdp_hdr); + + tx_buf[0] = 0x7f; + + memcpy(tx_buf + 1 + sizeof(struct pdp_hdr), buf, nbytes); + + tx_buf[1 + hdr->len] = 0x7e; + + ret = + dpram_write(&dpram_table[RAW_INDEX], tx_buf, hdr->len + 2); + + if (ret < 0) { + LOGE("write_to_dpram() failed: %d\n", ret); + /* check curent context */ + if (in_softirq_context) + spin_unlock(&mux_tty_lock); + else + spin_unlock_bh(&mux_tty_lock); + + return ret; + } + buf += nbytes; + len -= nbytes; + } + + /* check curent context */ + if (in_softirq_context) + spin_unlock(&mux_tty_lock); + else + spin_unlock_bh(&mux_tty_lock); + + return 0; + +} + + +static int vs_write(struct tty_struct *tty, + const unsigned char *buf, int count) +{ + int ret; + struct pdp_info *dev = (struct pdp_info *)tty->driver_data; + //PRINT_FUNC(); + ret = pdp_mux(dev, buf, count); + + if (ret == 0) + { + ret = count; + } + + return ret; +} + +static int vs_write_room(struct tty_struct *tty) +{ +// return TTY_FLIPBUF_SIZE; + return 8192*2; +} + +static int vs_chars_in_buffer(struct tty_struct *tty) +{ + return 0; +} + +static int vs_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +static struct tty_operations multipdp_tty_ops = { + .open = vs_open, + .close = vs_close, + .write = vs_write, + .write_room = vs_write_room, + .ioctl = vs_ioctl, + .chars_in_buffer = vs_chars_in_buffer, + + /* TODO: add more operations */ +}; + +static struct tty_driver* get_tty_driver_by_id(struct pdp_info *dev) +{ + int index = 0; + + switch (dev->id) { + case 1: index = 0; break; + case 7: index = 1; break; + case 29: index = 2; break; + default: index = 0; + } + + return &dev->vs_dev.tty_driver[index]; +} + +static int get_minor_start_index(int id) +{ + int start = 0; + + switch (id) { + case 1: start = 0; break; + case 7: start = 1; break; + case 29: start = 2; break; + default: start = 0; + } + + return start; +} + +static int vs_add_dev(struct pdp_info *dev) +{ + struct tty_driver *tty_driver; + + tty_driver = get_tty_driver_by_id(dev); + + if (!tty_driver) + { + LOGE("tty driver == NULL!\n"); + return -1; + } + + kref_init(&tty_driver->kref); + + tty_driver->magic = TTY_DRIVER_MAGIC; + tty_driver->driver_name = APP_DEVNAME;//"multipdp"; + tty_driver->name = dev->vs_dev.tty_name; + tty_driver->major = CSD_MAJOR_NUM; + tty_driver->minor_start = get_minor_start_index(dev->id); + tty_driver->num = 1; + tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + tty_driver->subtype = SERIAL_TYPE_NORMAL; + tty_driver->flags = TTY_DRIVER_REAL_RAW; +// kref_set(&tty_driver->kref, dev->vs_dev.refcount); + tty_driver->ttys = dev->vs_dev.tty_table; // 2.6 kernel porting + tty_driver->termios = dev->vs_dev.termios; + tty_driver->termios_locked = dev->vs_dev.termios_locked; + + tty_set_operations(tty_driver, &multipdp_tty_ops); + return tty_register_driver(tty_driver); +} + +static void vs_del_dev(struct pdp_info *dev) +{ + struct tty_driver *tty_driver = NULL; + + tty_driver = get_tty_driver_by_id(dev); + tty_unregister_driver(tty_driver); +} + +static inline void check_pdp_table(const char * func, int line) +{ + int slot; + for (slot = 0; slot < MAX_PDP_CONTEXT; slot++) + { + if (pdp_table[slot]) + LOGA("[%s,%d] addr: %x slot: %d id: %d, name: %s\n", func, line, + (u32)pdp_table[slot], slot, pdp_table[slot]->id, + pdp_table[slot]->vs_dev.tty_name); + } +} + +static inline struct pdp_info * pdp_get_dev(u8 id) +{ + int slot; + + for (slot = 0; slot < MAX_PDP_CONTEXT; slot++) + { + if (pdp_table[slot] && pdp_table[slot]->id == id) + { + return pdp_table[slot]; + } + } + return NULL; +} + +static inline int pdp_add_dev(struct pdp_info *dev) +{ + int slot; + + if (pdp_get_dev(dev->id)) { + return -EBUSY; + } + + for (slot = 0; slot < MAX_PDP_CONTEXT; slot++) { + if (pdp_table[slot] == NULL) { + pdp_table[slot] = dev; + return slot; + } + } + return -ENOSPC; +} + +static int pdp_activate(pdp_arg_t *pdp_arg, unsigned type, unsigned flags) +{ + int ret; + struct pdp_info *dev; + + LOGL(DL_INFO, "id: %d\n", pdp_arg->id); + //PRINT_FUNC(); + dev = kmalloc(sizeof(struct pdp_info) + MAX_PDP_PACKET_LEN, GFP_KERNEL); + if (dev == NULL) { + LOGE("out of memory\n"); + return -ENOMEM; + } + memset(dev, 0, sizeof(struct pdp_info)); + + dev->id = pdp_arg->id; + + dev->type = type; + dev->flags = flags; + dev->tx_buf = (u8 *)(dev + 1); + + if (type == DEV_TYPE_SERIAL) { + sema_init(&dev->vs_dev.write_lock, 1); + strcpy(dev->vs_dev.tty_name, pdp_arg->ifname); + + ret = vs_add_dev(dev); + if (ret < 0) { + kfree(dev); + return ret; + } + + mutex_lock(&pdp_lock); + ret = pdp_add_dev(dev); + if (ret < 0) { + LOGE("pdp_add_dev() failed\n"); + mutex_unlock(&pdp_lock); + vs_del_dev(dev); + kfree(dev); + return ret; + } + mutex_unlock(&pdp_lock); + + { + struct tty_driver * tty_driver = get_tty_driver_by_id(dev); +#ifndef PRODUCT_SHIP + LOGL(DL_INFO, "%s(id: %u) serial device is created.\n", + tty_driver->name, dev->id); +#endif + } + } + + return 0; +} + +static int multipdp_init(void) +{ + int i; + + pdp_arg_t pdp_args[NUM_PDP_CONTEXT] = { + { .id = 1, .ifname = "ttyCSD" }, + { .id = 7, .ifname = "ttyCDMA" }, + { .id = 29, .ifname = "ttyCPLOG" }, + // { .id = 31, .ifname = "loopback" }, + + }; + + + /* create serial device for Circuit Switched Data */ + for (i = 0; i < NUM_PDP_CONTEXT; i++) { + if (pdp_activate(&pdp_args[i], DEV_TYPE_SERIAL, DEV_FLAG_STICKY) < 0) { + LOGE("failed to create a serial device for %s\n", pdp_args[i].ifname); + } + } + + return 0; +} + +/* + * DPRAM DRIVER INITIALIZE FUNCTIONs + */ +static int dpram_init_hw(void) +{ + int rv; + + PRINT_FUNC(); + + + //1) Initialize the interrupt pins + // set_irq_type(IRQ_DPRAM_AP_INT_N, IRQ_TYPE_LEVEL_LOW); + /*irq_set_irq_type(IRQ_DPRAM_AP_INT_N, IRQ_TYPE_LEVEL_LOW);*/ + + rv = gpio_request(IRQ_QSC_INT, "gpx1_0"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_0\n",__func__); + goto err; + } + + dpram_wakeup_irq = gpio_to_irq(IRQ_QSC_INT); + + s3c_gpio_cfgpin(GPIO_C210_DPRAM_INT_N, S3C_GPIO_SFN(0xFF)); + s3c_gpio_setpull(GPIO_C210_DPRAM_INT_N, S3C_GPIO_PULL_NONE); + irq_set_irq_type(dpram_wakeup_irq, IRQ_TYPE_EDGE_RISING); + + rv = gpio_request(IRQ_QSC_PHONE_ACTIVE, "gpx1_6"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_6\n",__func__); + goto err1; + } + + phone_active_irq = gpio_to_irq(IRQ_QSC_PHONE_ACTIVE); + + s3c_gpio_setpull(GPIO_QSC_PHONE_ACTIVE, S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(GPIO_QSC_PHONE_RST, S3C_GPIO_PULL_NONE); +// set_irq_type(IRQ_QSC_ACTIVE, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(phone_active_irq, IRQ_TYPE_EDGE_FALLING); + + + rv = gpio_request(IRQ_CP_DUMP_INT, "gpx1_2"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_2\n",__func__); + goto err6; + } + + cp_dump_irq = gpio_to_irq(IRQ_CP_DUMP_INT); + + s3c_gpio_cfgpin(GPIO_CP_DUMP_INT, S3C_GPIO_SFN(0xFF)); + s3c_gpio_setpull(GPIO_CP_DUMP_INT, S3C_GPIO_PULL_DOWN); + irq_set_irq_type(cp_dump_irq, IRQ_TYPE_EDGE_RISING); + + + + // 2)EINT15 : QSC_ACTIVE (GPIO_INTERRUPT) +// #define FILTER_EINT15_EN (0x1<<31) +// #define FILTER_EINT15_SEL_DEGIT (0x1<<30) +//__raw_writel(__raw_readl(S5PV210_EINT1FLTCON1)|(FILTER_EINT15_EN & (~FILTER_EINT15_SEL_DEGIT)),S5PV210_EINT1FLTCON1); + + //3)EINT09 : QSC_INT (GPIO_INTERRUPT) +// #define FILTER_EINT9_EN (0x1<<15) +// #define FILTER_EINT9_SEL_DEGIT (0x1<<14) +//__raw_writel(__raw_readl(S5PV210_EINT1FLTCON0)|(FILTER_EINT9_EN & (~FILTER_EINT9_SEL_DEGIT)),S5PV210_EINT1FLTCON0); + + + // 4)gpio e3-e4 are for Modem if + + s3c_gpio_cfgpin(S5PV310_GPE3_0_MDM_DATA_0, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_1_MDM_DATA_1, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_2_MDM_DATA_2, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_3_MDM_DATA_3, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_4_MDM_DATA_4, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_5_MDM_DATA_5, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_6_MDM_DATA_6, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_7_MDM_DATA_7, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + s3c_gpio_cfgpin(S5PV310_GPE4_0_MDM_DATA_8, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_1_MDM_DATA_9, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_2_MDM_DATA_10, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_3_MDM_DATA_11, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_4_MDM_DATA_12, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_5_MDM_DATA_13, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_6_MDM_DATA_14, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_7_MDM_DATA_15, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + s3c_gpio_cfgpin(S5PV310_GPE0_0_MDM_WEn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_1_MDM_CSn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_2_MDM_Rn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_3_MDM_IRQn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_4_MDM_ADVN, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + rv = gpio_request(GPIO_PDA_ACTIVE, "GPY4_2"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPY4_2\n",__func__); + goto err2; + } + + rv = gpio_request(GPIO_QSC_PHONE_ON, "GPC1_1"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPC1_1\n",__func__); + goto err3; + } + + rv = gpio_request(GPIO_QSC_PHONE_RST, "GPX1_4"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_4\n",__func__); + goto err4; + } + + s5p_gpio_set_drvstr(GPIO_QSC_PHONE_RST, S5P_GPIO_DRVSTR_LV4); //To increase driving strength of this pin + + //To config Not Connected pin GPY4_6 to I/P with no pullup + rv = gpio_request(GPIO_CP_REQ_RESET, "GPY4_6"); + if(rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPY4_6\n",__func__); + goto err5; + } + + gpio_direction_input(GPIO_CP_REQ_RESET); + s3c_gpio_setpull(GPIO_CP_REQ_RESET, S3C_GPIO_PULL_NONE); + + // 5)PDA_ACTIVE, QSC_PHONE_ON, QSC_RESET_N + gpio_direction_output(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + s3c_gpio_setpull(GPIO_QSC_PHONE_ON, S3C_GPIO_PULL_NONE); + gpio_direction_output(GPIO_QSC_PHONE_RST, GPIO_LEVEL_LOW); + + return 0; + +err6: gpio_free(IRQ_CP_DUMP_INT); +err5: gpio_free(GPIO_QSC_PHONE_RST); +err4: gpio_free(GPIO_QSC_PHONE_ON); +err3: gpio_free(GPIO_PDA_ACTIVE); +err2: gpio_free(IRQ_QSC_PHONE_ACTIVE); +err1: gpio_free(IRQ_QSC_INT); +err: return rv; +} + + +static int dpram_shared_bank_remap(void) +{ + +//Clock Settings for Modem IF ====>FixMe + u32 val; + void __iomem *regs = ioremap(0x10030000, 0x10000); + //PRINT_FUNC(); + //Enabling Clock for ModemIF in Reg CLK_GATE_IP_PERIL:0x1003C950 + val = readl(regs + 0xC950); + val |= 0x10000000; + writel(val, regs + 0xC950); + iounmap(regs); + + //3 Get internal DPRAM / SFR Virtual address [[ + // 1) dpram base + idpram_base = (volatile void __iomem *)ioremap_nocache(IDPRAM_PHYSICAL_ADDR, IDPRAM_SIZE); + if (idpram_base == NULL) + { + LOGE("Failed!!! (idpram_base == NULL)\n"); + return -1; + } + LOGA("BUF PA = 0x%08X, VA = 0x%08X\n", (u32)IDPRAM_PHYSICAL_ADDR, + (u32)idpram_base); + + // 2) sfr base + idpram_sfr_base = (volatile IDPRAM_SFR __iomem *)ioremap_nocache(IDPRAM_SFR_PHYSICAL_ADDR, IDPRAM_SFR_SIZE); + if (idpram_sfr_base == NULL) + { + LOGE("Failed!!! (idpram_sfr_base == NULL)\n"); + iounmap(idpram_base); + return -1; + } + LOGA("SFR PA = 0x%08X, VA = 0x%08X\n", (u32)IDPRAM_SFR_PHYSICAL_ADDR, + (u32)idpram_sfr_base); + + // 3) Initialize the Modem interface block(internal DPRAM) + // TODO : Use DMA controller? ask to sys.lsi + // set Modem interface config register + idpram_sfr_base->mifcon = (IDPRAM_MIFCON_FIXBIT|IDPRAM_MIFCON_INT2APEN|IDPRAM_MIFCON_INT2MSMEN); //FIXBIT enable, interrupt enable AP,MSM(CP) + idpram_sfr_base->mifpcon = (IDPRAM_MIFPCON_ADM_MODE); //mux mode + + dpram_mbx_BA = (volatile u16*)(idpram_base + IDPRAM_AP2MSM_INT_OFFSET); + dpram_mbx_AB = (volatile u16*)(idpram_base + IDPRAM_MSM2AP_INT_OFFSET); + LOGA("VA of mbx_BA = 0x%08X, VA of mbx_AB = 0x%08X\n", (u32)dpram_mbx_BA, + (u32)dpram_mbx_AB); + + // write the normal boot magic key for CDMA boot + *((unsigned int *)idpram_base) = DPRAM_BOOT_NORMAL; + + atomic_set(&dpram_read_lock, 0); + atomic_set(&dpram_write_lock, 0); + + return 0; +} + +static void dpram_init_devices(void) +{ + int i; + + for (i = 0; i < MAX_INDEX; i++) { + //init_MUTEX(&dpram_table[i].serial.sem); + sema_init(&dpram_table[i].serial.sem, 1); + + dpram_table[i].serial.open_count = 0; + dpram_table[i].serial.tty = NULL; + } +} + +void dpram_wakeup_init(void) +{ + idpram_sfr_base->mifcon = (IDPRAM_MIFCON_FIXBIT|IDPRAM_MIFCON_INT2APEN|IDPRAM_MIFCON_INT2MSMEN); + idpram_sfr_base->mifpcon = (IDPRAM_MIFPCON_ADM_MODE); + + // mux GPIO_DPRAM_INT_CP_N to dpram interrupt + + s3c_gpio_cfgpin(S5PV310_GPE0_0_MDM_WEn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_1_MDM_CSn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_2_MDM_Rn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_3_MDM_IRQn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_4_MDM_ADVN, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + +} + +#define WAKESTART_TIMEOUT (HZ/10) +#define WAKESTART_TIMEOUT_RETRY 5 + +void dpram_wait_wakeup_start(void) +{ + int wakeup_retry = WAKESTART_TIMEOUT_RETRY; + int timeout_ret = 0; + + do { + init_completion(&g_complete_dpramdown); + dpram_send_mbx_BA_cmd(INT_COMMAND(MBX_CMD_PDA_WAKEUP)); + timeout_ret = wait_for_completion_timeout(&g_complete_dpramdown, WAKESTART_TIMEOUT); + } while(!timeout_ret && wakeup_retry--); + + if (!timeout_ret) + { + LOGE("T-I-M-E-O-U-T !!!\n"); + } + + g_dpram_wpend = IDPRAM_WPEND_UNLOCK; // dpram write unlock +} + +static void kill_tasklets(void) +{ + tasklet_kill(&fmt_res_ack_tasklet); + tasklet_kill(&raw_res_ack_tasklet); + + tasklet_kill(&fmt_send_tasklet); + tasklet_kill(&raw_send_tasklet); +} + +static int register_interrupt_handler(void) +{ + int retval = 0; + + dpram_irq = IRQ_DPRAM_AP_INT_N; + + dpram_clear(); + + //1)dpram interrupt + IDPRAM_INT_CLEAR(); + retval = request_irq(dpram_irq, dpram_irq_handler, IRQF_TRIGGER_NONE, "DPRAM irq", NULL); + if (retval) + { + LOGE("DPRAM interrupt handler failed.\n"); + unregister_dpram_driver(); + return -1; + } + + //2) wake up for internal dpram + + retval = request_irq(dpram_wakeup_irq, dpram_wake_from_CP_irq_handler, IRQF_DISABLED, "QSC_INT irq", NULL); + if (retval) + { + LOGE("DPRAM wakeup interrupt handler failed.\n"); + free_irq(dpram_irq, NULL); + unregister_dpram_driver(); + return -1; + } + enable_irq_wake(dpram_wakeup_irq); + + //3) phone active interrupt + retval = request_irq(phone_active_irq, phone_active_irq_handler, IRQF_DISABLED, "QSC_ACTIVE", NULL); + if (retval) + { + LOGE("Phone active interrupt handler failed.\n"); + free_irq(dpram_irq, NULL); + free_irq(dpram_wakeup_irq, NULL); + unregister_dpram_driver(); + return -1; + } + enable_irq_wake(phone_active_irq); + + + //4) cp dump int interrupt for LPA mode + retval = request_irq(cp_dump_irq, cp_dump_irq_handler, IRQF_DISABLED, "CP_DUMP_INT irq", NULL); + if (retval) + { + LOGE("CP_DUMP_INT interrupt handler failed.\n"); + free_irq(dpram_irq, NULL); + free_irq(dpram_wakeup_irq, NULL); + free_irq(phone_active_irq, NULL); + unregister_dpram_driver(); + return -1; + } + enable_irq_wake(cp_dump_irq); + + + + return 0; +} + +static void check_miss_interrupt(void) +{ + unsigned long flags; + + if (gpio_get_value(GPIO_QSC_PHONE_ACTIVE) && \ + !gpio_get_value(GPIO_DPRAM_INT_CP_N)) { + printk(KERN_INFO "[IDPRAM] %s", __func__); + local_irq_save(flags); + dpram_irq_handler(IRQ_DPRAM_AP_INT_N, NULL); + local_irq_restore(flags); + } +} + +/* + * INTERANL DPRAM POWER DOWN FUNCTION + */ + + +/* + * void dpram_power_down() + * + * This function release the wake_lock + * Phone send DRPAM POWER DOWN interrupt and handler call this function. + */ +static void dpram_power_down(void) +{ +#ifdef PRINT_DPRAM_PWR_CTRL + LOGA("Received MBX_CMD_DPRAM_DOWN (lock count = %d)!!!\n", + dpram_get_lock_read()); +#endif + complete(&g_complete_dpramdown); +} + + +static void dpram_powerup_start(void) +{ +#ifdef PRINT_DPRAM_PWR_CTRL + LOGA("Received MBX_CMD_CP_WAKEUP_START!!!\n"); +#endif + complete(&g_complete_dpramdown); +} + + +/* + * void dpram_power_up() + * + * Initialize dpram when ap wake up and send WAKEUP_INT to phone + * This function will be called by Onedram_resume() + */ +static inline void dpram_power_up(void) +{ + const u16 magic_code = 0x00AA; + u16 acc_code = 0x0001; + + dpram_clear(); + + WRITE_TO_DPRAM(DPRAM_MAGIC_CODE_ADDRESS, &magic_code, sizeof(magic_code)); + WRITE_TO_DPRAM(DPRAM_ACCESS_ENABLE_ADDRESS, &acc_code, sizeof(acc_code)); + + // Initialize the dpram controller + dpram_wakeup_init(); + +#ifdef PRINT_DPRAM_PWR_CTRL + // Check for QSC_INT for debugging + LOGA("dpram_wakeup_init() ==> QSC_INT = %s\n", + gpio_get_value(GPIO_QSC_INT) ? "HIGH" : "LOW"); +#endif +} + + +/* + * DPRAM DRIVER FUNCTIONs + */ +#define DPRAMDOWN_TIMEOUT (HZ * 3) +#define DPRAM_PDNINTR_RETRY_CNT 2 + +/* +** lock the AP write dpram and send the SLEEP INT to Phone +*/ +static int dpram_suspend(struct platform_device *dev, pm_message_t state) +{ + u16 in_intr = 0; + u16 timeout_ret = 0; + u16 suspend_retry = DPRAM_PDNINTR_RETRY_CNT; + + g_dpram_wpend = IDPRAM_WPEND_LOCK; // dpram write lock + + /* + ** if some intrrupt was received by cp, dpram hold the wake lock and pass the suspend mode. + */ + if (dpram_get_lock_read() == 0) + { + /* + ** retry sending MBX_CMD_PDA_SLEEP if CP does not send in timout + */ + do { + init_completion(&g_complete_dpramdown); + dpram_send_mbx_BA_cmd(INT_COMMAND(MBX_CMD_PDA_SLEEP)); + //timeout_ret = wait_for_completion_timeout(&g_complete_dpramdown, DPRAMDOWN_TIMEOUT); + timeout_ret = wait_for_completion_timeout(&g_complete_dpramdown, msecs_to_jiffies(500)); +#ifdef PRINT_DPRAM_PWR_CTRL + LOGA("suspend_enter cnt = %d\n", (DPRAM_PDNINTR_RETRY_CNT - suspend_retry)); +#endif + } while ( !timeout_ret && suspend_retry-- ); + + in_intr = ioread16((void *)dpram_mbx_AB); + if (in_intr != (INT_MASK_VALID|INT_MASK_COMMAND|MBX_CMD_DPRAM_DOWN)) + { + LOGE("T-I-M-E-O-U-T !!! (intr = 0x%04X)\n", in_intr); + g_dpram_wpend = IDPRAM_WPEND_UNLOCK; // dpram write unlock + + if (g_phone_sync == 0) + { + LOGE("phone_sync: [%d] retry Phone reset and on\n", g_phone_sync); + dpram_phone_reset(); + dpram_phone_power_on(); + } + return -1; + } + + /* + * Because, if dpram was powered down, cp dpram random intr was ocurred, + * So, fixed by muxing cp dpram intr pin to GPIO output high,.. + */ + gpio_set_value(S5PV310_GPE0_3_MDM_IRQn, GPIO_LEVEL_HIGH); + + s3c_gpio_cfgpin(S5PV310_GPE0_0_MDM_WEn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_1_MDM_CSn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_2_MDM_Rn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_3_MDM_IRQn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_4_MDM_ADVN, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + gpio_set_value(GPIO_PDA_ACTIVE, GPIO_LEVEL_LOW); + + flush_work(&phone_active_work.work); + + //To configure AP_WAKE wakable interrupt + /* block this irq diable routine.*/ + /* When CP send the interrupt after dpram_susepnd, */ + /*int pending resister is not set until CPU sleep.*/ + /* Becuase irq is disabled.*/ + /*disable_irq(dpram_wakeup_irq); + enable_irq_wake(dpram_wakeup_irq);*/ + } + else + { + //wake_lock_timeout(&dpram_wake_lock, HZ/4); + LOGA("Skip the suspned mode - read lock \n"); + g_dpram_wpend = IDPRAM_WPEND_UNLOCK; // dpram write unlock + return -1; + } + + return 0; +} + + +static int dpram_resume(struct platform_device *dev) +{ + gpio_set_value(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + + dpram_power_up(); + dpram_wait_wakeup_start(); // wait the CP ack 0xCE + + //To configure AP_WAKE normal interrupt + /*disable_irq_wake(dpram_wakeup_irq); + enable_irq(dpram_wakeup_irq);*/ + + /*check_miss_interrupt();*/ + return 0; +} + + +static int __devinit dpram_probe(struct platform_device *dev) +{ + int retval; + + PRINT_FUNC(); + + retval = register_dpram_driver(); + if (retval) { + LOGE("Failed to register dpram (tty) driver.\n"); + return -1; + } + + LOGA("register_dpram_driver() success!!!\n"); + +#ifdef _ENABLE_ERROR_DEVICE + retval = register_dpram_err_device(); + if (retval) { + LOGE("Failed to register dpram error device. (%d)\n", retval); + unregister_dpram_driver(); + return -1; + } + memset((void *)dpram_err_buf, 0, sizeof(dpram_err_buf)); + LOGA("register_dpram_err_device() success!!!\n"); + + retval = register_dpram_dump_device(); + if (retval) { + LOGE("Failed to register dpram dump device. (%d)\n", retval); + unregister_dpram_driver(); + return -1; + } + memset((void *)cp_ramdump_buff, 0, sizeof(cp_ramdump_buff)); + LOGA("register_dpram_dump_device() success!!!\n"); + + init_completion(&wait_dump_data); +#endif /* _ENABLE_ERROR_DEVICE */ + + retval = misc_register(&multipdp_dev); /* create app. interface device */ + if (retval < 0) + { + LOGE("misc_register() failed\n"); + return -1; + } + + multipdp_init(); + + retval = dpram_init_hw(); + if (retval < 0) + { + LOGE("dpram_init_hw() failed\n"); + return -1; + } + + dpram_shared_bank_remap(); + + //3 DJ07 Dr.J ADD [[ + iowrite16(0, (void *)(DPRAM_VBASE + DPRAM_MAGIC_CODE_ADDRESS)); + iowrite16(0, (void *)(DPRAM_VBASE + DPRAM_ACCESS_ENABLE_ADDRESS)); + dpram_clear(); + //3 ]] + + dpram_init_devices(); + + atomic_set(&raw_txq_req_ack_rcvd, 0); + atomic_set(&fmt_txq_req_ack_rcvd, 0); + + wake_lock_init(&dpram_wake_lock, WAKE_LOCK_SUSPEND, "DPRAM_PWDOWN"); + INIT_DELAYED_WORK(&phone_active_work, phone_active_work_func); + + retval = register_interrupt_handler(); + if ( retval < 0 ) + { + LOGE("register_interrupt_handler() failed!!!\n"); + + gpio_free(IRQ_CP_DUMP_INT); + gpio_free(GPIO_QSC_PHONE_RST); + gpio_free(GPIO_QSC_PHONE_ON); + gpio_free(GPIO_PDA_ACTIVE); + gpio_free(IRQ_QSC_PHONE_ACTIVE); + gpio_free(IRQ_QSC_INT); + + return -1; + } + +#ifdef CONFIG_PROC_FS + create_proc_read_entry(DRIVER_PROC_ENTRY, 0, 0, dpram_read_proc, NULL); +#endif /* CONFIG_PROC_FS */ +//DI20 Dr.J ... cdma_slot_switch_handler = slot_switch_handler2; + + //check_miss_interrupt(); + init_completion(&g_complete_dpramdown); + printk("IDPRAM: DPRAM driver is registered !!!\n"); + + return 0; +} + +static int __devexit dpram_remove(struct platform_device *dev) +{ + //PRINT_FUNC(); + + free_irq(IRQ_DPRAM_AP_INT_N, NULL); + free_irq(phone_active_irq, NULL); + free_irq(dpram_wakeup_irq, NULL); + free_irq(cp_dump_irq, NULL); + + /* @LDK@ unregister dpram (tty) driver */ + unregister_dpram_driver(); + + /* @LDK@ unregister dpram error device */ +#ifdef _ENABLE_ERROR_DEVICE + unregister_dpram_err_device(); + unregister_dpram_dump_device(); +#endif + + /* remove app. interface device */ + misc_deregister(&multipdp_dev); + + wake_lock_destroy(&dpram_wake_lock); + + gpio_free(IRQ_CP_DUMP_INT); + gpio_free(GPIO_QSC_PHONE_RST); + gpio_free(GPIO_QSC_PHONE_ON); + gpio_free(GPIO_PDA_ACTIVE); + gpio_free(IRQ_QSC_PHONE_ACTIVE); + gpio_free(IRQ_QSC_INT); + + flush_work(&phone_active_work.work); + kill_tasklets(); + + return 0; +} + +static void dpram_shutdown(struct platform_device *dev) +{ + dpram_remove(dev); +} + +u32 dpram_get_phone_dump_stat(void) +{ + return g_dump_on; +} + +EXPORT_SYMBOL(dpram_get_phone_dump_stat); + +static struct platform_driver platform_dpram_driver = { + .probe = dpram_probe, + .remove = __devexit_p(dpram_remove), + .suspend = dpram_suspend, + .resume = dpram_resume, + .shutdown = dpram_shutdown, + .driver = { + .name = "dpram-device", + }, +}; + +/* init & cleanup. */ +static int __init dpram_init(void) +{ + + return platform_driver_register(&platform_dpram_driver); +} + +static void __exit dpram_exit(void) +{ + platform_driver_unregister(&platform_dpram_driver); +} + +module_init(dpram_init); +module_exit(dpram_exit); + +MODULE_AUTHOR("SAMSUNG ELECTRONICS CO., LTD"); +MODULE_DESCRIPTION("Internal DPRAM Device Driver."); +MODULE_LICENSE("GPL"); diff --git a/drivers/dpram/raffaello/dpram.h b/drivers/dpram/raffaello/dpram.h new file mode 100755 index 0000000..c6ed226 --- /dev/null +++ b/drivers/dpram/raffaello/dpram.h @@ -0,0 +1,418 @@ +/**************************************************************************** + +** + +** COPYRIGHT(C) : Samsung Electronics Co.Ltd, 2006-2010 ALL RIGHTS RESERVED + +** + +** AUTHOR : Kim, Geun-Young <geunyoung.kim@samsung.com> @LDK@ + +** @LDK@ + +****************************************************************************/ + +#ifndef __IDPRAM_H__ +#define __IDPRAM_H__ + +/* +** FEATURE DEFINITIONs +*/ +#define _DEBUG + +#define CDMA_IPC_C210_IDPRAM +#define DPRAM_SIZE_16KB + +//#define DPRAM_SIZE_32KB + +#if defined(DPRAM_SIZE_16KB) +/* +** DPRAM SETTINGS - 16K S5PC210 Internal DPRAM +*/ +#define DPRAM_SIZE 0x4000 /* 16KB */ +#define DPRAM_PDA2PHONE_FORMATTED_BUFFER_SIZE 1020 +#define DPRAM_PDA2PHONE_RAW_BUFFER_SIZE 7160 +#define DPRAM_PHONE2PDA_FORMATTED_BUFFER_SIZE 1020 +#define DPRAM_PHONE2PDA_RAW_BUFFER_SIZE 7160 +#define DPRAM_INTERRUPT_PORT_SIZE 2 +#elif defined(DPRAM_SIZE_32KB) +/* +** DPRAM SETTINGS - 32K External DPRAM +*/ +#define DPRAM_SIZE 0x8000 /* 32 KB */ +#define DPRAM_PDA2PHONE_FORMATTED_BUFFER_SIZE 4092 +#define DPRAM_PDA2PHONE_RAW_BUFFER_SIZE 12272 +#define DPRAM_PHONE2PDA_FORMATTED_BUFFER_SIZE 4092 +#define DPRAM_PHONE2PDA_RAW_BUFFER_SIZE 12272 +#define DPRAM_INTERRUPT_PORT_SIZE 2 +#else +#error "Feature is neither DPRAM_SIZE_16KB nor DPRAM_SIZE_32KB" +#endif /*DPRAM_SIZE_16KB*/ + +/* +** Memory Offsets +*/ +#define DPRAM_START_ADDRESS 0x0000 + +#define DPRAM_MAGIC_CODE_ADDRESS (DPRAM_START_ADDRESS) +#define DPRAM_ACCESS_ENABLE_ADDRESS (DPRAM_START_ADDRESS + 0x0002) + +#define DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS (DPRAM_START_ADDRESS + 0x0004) +#define DPRAM_PDA2PHONE_FORMATTED_HEAD_ADDRESS (DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS) +#define DPRAM_PDA2PHONE_FORMATTED_TAIL_ADDRESS (DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS + 0x0002) +#define DPRAM_PDA2PHONE_FORMATTED_BUFFER_ADDRESS (DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS + 0x0004) + +#define DPRAM_PDA2PHONE_RAW_START_ADDRESS (DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS + DPRAM_PDA2PHONE_FORMATTED_BUFFER_SIZE + 4) +#define DPRAM_PDA2PHONE_RAW_HEAD_ADDRESS (DPRAM_PDA2PHONE_RAW_START_ADDRESS) +#define DPRAM_PDA2PHONE_RAW_TAIL_ADDRESS (DPRAM_PDA2PHONE_RAW_START_ADDRESS + 0x0002) +#define DPRAM_PDA2PHONE_RAW_BUFFER_ADDRESS (DPRAM_PDA2PHONE_RAW_START_ADDRESS + 0x0004) + +#define DPRAM_PHONE2PDA_FORMATTED_START_ADDRESS (DPRAM_PDA2PHONE_RAW_START_ADDRESS + DPRAM_PDA2PHONE_RAW_BUFFER_SIZE + 4) +#define DPRAM_PHONE2PDA_FORMATTED_HEAD_ADDRESS (DPRAM_PHONE2PDA_FORMATTED_START_ADDRESS) +#define DPRAM_PHONE2PDA_FORMATTED_TAIL_ADDRESS (DPRAM_PHONE2PDA_FORMATTED_START_ADDRESS + 0x0002) +#define DPRAM_PHONE2PDA_FORMATTED_BUFFER_ADDRESS (DPRAM_PHONE2PDA_FORMATTED_START_ADDRESS + 0x0004) + +#define DPRAM_PHONE2PDA_RAW_START_ADDRESS (DPRAM_PHONE2PDA_FORMATTED_START_ADDRESS + (DPRAM_PHONE2PDA_FORMATTED_BUFFER_SIZE + 4)) +#define DPRAM_PHONE2PDA_RAW_HEAD_ADDRESS (DPRAM_PHONE2PDA_RAW_START_ADDRESS) +#define DPRAM_PHONE2PDA_RAW_TAIL_ADDRESS (DPRAM_PHONE2PDA_RAW_START_ADDRESS + 0x0002) +#define DPRAM_PHONE2PDA_RAW_BUFFER_ADDRESS (DPRAM_PHONE2PDA_RAW_START_ADDRESS + 0x0004) + +#if defined(DPRAM_SIZE_16KB) +#define DPRAM_PDA2PHONE_INTERRUPT_ADDRESS 0x3FFC +#define DPRAM_PHONE2PDA_INTERRUPT_ADDRESS 0x3FFE +#elif defined(DPRAM_SIZE_32KB) +#define DPRAM_PDA2PHONE_INTERRUPT_ADDRESS 0x7FFC +#define DPRAM_PHONE2PDA_INTERRUPT_ADDRESS 0x7FFE +#else +#error "Feature is neither DPRAM_SIZE_16KB nor DPRAM_SIZE_32KB" +#endif + + +/* +** Logic Values +*/ +#define TRUE 1 +#define FALSE 0 + + +/* +** INTERRUPT MASKs +*/ +#define INT_MASK_VALID 0x0080 +#define INT_MASK_COMMAND 0x0040 +#define INT_MASK_REQ_ACK_F 0x0020 +#define INT_MASK_REQ_ACK_R 0x0010 +#define INT_MASK_RES_ACK_F 0x0008 +#define INT_MASK_RES_ACK_R 0x0004 +#define INT_MASK_SEND_F 0x0002 +#define INT_MASK_SEND_R 0x0001 + +/* +** INTERRUPT COMMANDs +*/ +#define MBX_CMD_INIT_START 0x0001 +#define MBX_CMD_INIT_END 0x0002 +#define MBX_CMD_REQ_ACTIVE 0x0003 +#define MBX_CMD_RES_ACTIVE 0x0004 +#define MBX_CMD_REQ_TIME_SYNC 0x0005 +#define MBX_CMD_PHONE_RESET 0x0007 +#define MBX_CMD_PHONE_START 0x0008 +#define MBX_CMD_PHONE_COMMON_BOOT 0x0108 +#define MBX_CMD_ERR_DISPLAY 0x0009 +#define MBX_CMD_PHONE_DEEP_SLEEP 0x000A + +#define MBX_CMD_DPRAM_DOWN 0x000B // DPRAM_DOWN Interrupt from Modem 0xCB +#define MBX_CMD_PDA_WAKEUP 0x000C // PDA Wake up Interrupt to Modem 0xCC +#define MBX_CMD_PDA_SLEEP 0x000D // PDA Sleep Interrupt to Modem 0xCD +#define MBX_CMD_CP_WAKEUP_START 0x000E // CP Send ack CE to PDA + +#define MBX_CMD_CDMA_DEAD 0xAB09 + +#define INT_COMMAND(x) (INT_MASK_VALID | INT_MASK_COMMAND | x) +#define INT_NON_COMMAND(x) (INT_MASK_VALID | x) + +/* special interrupt cmd indicating modem boot failure. */ +#define INT_POWERSAFE_FAIL 0xDEAD + +#define FORMATTED_INDEX 0 +#define RAW_INDEX 1 +#define MAX_INDEX 2 + + +/* +** IOCTL COMMANDs +*/ +#define IOC_MZ_MAGIC ('o') +#define DPRAM_PHONE_POWON _IO(IOC_MZ_MAGIC, 0xD0) +#define DPRAM_PHONEIMG_LOAD _IO(IOC_MZ_MAGIC, 0xD1) +#define DPRAM_NVDATA_LOAD _IO(IOC_MZ_MAGIC, 0xD2) +#define DPRAM_PHONE_BOOTSTART _IO(IOC_MZ_MAGIC, 0xD3) +#define DPRAM_PHONE_BOOTTYPE _IOW(IOC_MZ_MAGIC,0xD5, unsigned int) +//#define DPRAM_PHONE_OFF _IO(IOC_MZ_MAGIC,0xD6) +#define IOCTL_ONEDRAM_WAKEUP _IOW(IOC_MZ_MAGIC,0xD7, unsigned int) +//#define DPRAM_PHONE_RESET _IO(IOC_MZ_MAGIC,0xD8) +#define DPRAM_PHONE_RAM_DUMP _IO(IOC_MZ_MAGIC,0xD9) + +#define IOCTL_SET_FATAL_OPERATION _IOW(IOC_MZ_MAGIC,0xDA, unsigned int) + +#define IOC_SEC_MAGIC (0xF0) +#define DPRAM_PHONE_ON _IO(IOC_SEC_MAGIC, 0xC0) +#define DPRAM_PHONE_OFF _IO(IOC_SEC_MAGIC, 0xC1) +#define DPRAM_PHONE_GETSTATUS _IOR(IOC_SEC_MAGIC, 0xC2, unsigned int) +//#define DPRAM_PHONE_MDUMP _IO(IOC_SEC_MAGIC, 0xC3) +//#define DPRAM_PHONE_BATTERY _IO(IOC_SEC_MAGIC, 0xC4) +#define DPRAM_PHONE_RESET _IO(IOC_SEC_MAGIC, 0xC5) +#define DPRAM_PHONE_RAMDUMP_ON _IO(IOC_SEC_MAGIC, 0xC6) +#define DPRAM_PHONE_RAMDUMP_OFF _IO(IOC_SEC_MAGIC, 0xC7) +#define DPRAM_EXTRA_MEM_RW _IOWR(IOC_SEC_MAGIC, 0xC8, unsigned long) + +#define DPRAM_PHONE_UNSET_UPLOAD _IO(IOC_SEC_MAGIC, 0xCA) +#define DPRAM_PHONE_SET_AUTOTEST _IO(IOC_SEC_MAGIC, 0xCB) +#define DPRAM_PHONE_SET_DEBUGLEVEL _IO(IOC_SEC_MAGIC, 0xCC) +#define DPRAM_PHONE_GET_DEBUGLEVEL _IO(IOC_SEC_MAGIC, 0xCD) + +#define DPRAM_PHONE_CPRAMDUMP_START _IO(IOC_SEC_MAGIC, 0xCE) +#define DPRAM_PHONE_CPRAMDUMP_DONE _IO(IOC_SEC_MAGIC, 0xCF) + +#define CP_RESET_CODE 0xCDABCDAB + +/* + * COMMON BOOT DEFINITIONs + */ +#define CP_CHIPSET_QUALCOMM 0x100 +#define CP_CHIPSET_INFINEON 0x200 +#define CP_CHIPSET_BROADCOM 0x300 +#define AP_PLATFORM_ANDROID 0x100 +#define AP_PLATFORM_LINUX 0x300 +#define CP_ONLINE_BOOT 0x0000 +#define CP_AIRPLANE_BOOT 0x1000 + +/* + * BOOT MAGIC KEY + */ +#define DPRAM_BOOT_NORMAL (('T'<<24) | ('B'<<16) | ('M'<<8) | 'N') + + +#ifdef CDMA_IPC_C210_IDPRAM +#define DPRAM_VBASE idpram_base + +/* +** S5PC11x DPRAM REGISTER MAP +*/ +#ifndef IDPRAM_PHYSICAL_ADDR +#define IDPRAM_PHYSICAL_ADDR S5P_PA_MODEMIF +#endif +#define IDPRAM_START_ADDR ((volatile void __iomem *)idpram_base) +#define IDPRAM_SIZE 0x4000 + +#define IDPRAM_AP2MSM_INT_OFFSET 0x3FFC +#define IDPRAM_MSM2AP_INT_OFFSET 0x3FFE + +#define IDPRAM_SFR_PHYSICAL_ADDR (IDPRAM_PHYSICAL_ADDR + 0x8000) +#define IDPRAM_SFR_START_ADDR ((volatile void __iomem *)idpram_sfr_base) +#define IDPRAM_SFR_INT2AP (IDPRAM_SFR_START_ADDR) +#define IDPRAM_SFR_INT2MSM (IDPRAM_SFR_START_ADDR + 0x4) +#define IDPRAM_SFR_MIFCON (IDPRAM_SFR_START_ADDR + 0x8) +#define IDPRAM_SFR_MIFPCON (IDPRAM_SFR_START_ADDR + 0xC) +#define IDPRAM_SFR_MSMINTCLR (IDPRAM_SFR_START_ADDR + 0x10) +#define IDPRAM_SFR_DMA_TX_ADR (IDPRAM_SFR_START_ADDR + 0x14) +#define IDPRAM_SFR_DMA_RX_ADR (IDPRAM_SFR_START_ADDR + 0x18) +#define IDPRAM_SFR_SIZE 0x1C + +// It is recommended that S5PC110 write data with half-word access on the interrupt port because +// S5PC100 overwrites tha data in INT2AP if there are INT2AP and INT2MSM sharing the same word +#define IDPRAM_INT2MSM_MASK 0xFF + +#define IDPRAM_MIFCON_INT2APEN (1<<2) +#define IDPRAM_MIFCON_INT2MSMEN (1<<3) +#define IDPRAM_MIFCON_DMATXREQEN_0 (1<<16) +#define IDPRAM_MIFCON_DMATXREQEN_1 (1<<17) +#define IDPRAM_MIFCON_DMARXREQEN_0 (1<<18) +#define IDPRAM_MIFCON_DMARXREQEN_1 (1<<19) +#define IDPRAM_MIFCON_FIXBIT (1<<20) + +#define IDPRAM_MIFPCON_ADM_MODE (1<<6) // mux / demux mode + +#define IDPRAM_DMA_ADR_MASK 0x3FFF +#define IDPRAM_DMA_TX_ADR_0 // shift 0 +#define IDPRAM_DMA_TX_ADR_1 // shift 16 +#define IDPRAM_DMA_RX_ADR_0 // shift 0 +#define IDPRAM_DMA_RX_ADR_1 // shift 16 + +#define IDPRAM_INT_CLEAR() idpram_sfr_base->msmintclr = 0xFF + +typedef struct { + unsigned int int2ap; + unsigned int int2msm; + unsigned int mifcon; + unsigned int mifpcon; + unsigned int msmintclr; + unsigned int dma_tx_adr; + unsigned int dma_rx_adr; +} IDPRAM_SFR; +#endif + +/* +** DEVICE DEFINITIONs +*/ +#define DRIVER_NAME "DPRAM" +#define DRIVER_PROC_ENTRY "driver/dpram" +#define DRIVER_MAJOR_NUM 249 +#define DPRAM_DUMP_DEV_MAJOR 250 + +/* +** MULTI PDP DEFINITIONs +*/ +#define APP_DEVNAME "multipdp" /* Device node name for application interface */ +#define NUM_PDP_CONTEXT 3 /* number of PDP context */ +/* Device types */ +#define DEV_TYPE_NET 0 /* network device for IP data */ +#define DEV_TYPE_SERIAL 1 /* serial device for CSD */ +#define CSD_MAJOR_NUM 248 /* Device major number */ +#define CSD_MINOR_NUM 0 /* Device minor number */ +#define MAX_PDP_CONTEXT 10 /* Maximum number of PDP context */ +#define MAX_PDP_DATA_LEN 1500 /* Maximum PDP data length */ +/* Device flags */ +#define DEV_FLAG_STICKY 0x1 /* Sticky */ +/* Maximum PDP packet length including header and start/stop bytes */ +#define MAX_PDP_PACKET_LEN (MAX_PDP_DATA_LEN + 4 + 2) + + +typedef struct pdp_arg { + unsigned char id; + char ifname[16]; +} __attribute__ ((packed)) pdp_arg_t; /* Multiple PDP */ + + +struct pdp_hdr { + u16 len; /* Data length */ + u8 id; /* Channel ID */ + u8 control; /* Control field */ +} __attribute__ ((packed)); /* PDP data packet header format */ + + +/* PDP information type */ +struct pdp_info { + u8 id; /* PDP context ID */ + unsigned type; /* Device type */ + unsigned flags; /* Device flags */ + u8 *tx_buf; /* Tx packet buffer */ + union { + struct { + struct tty_driver tty_driver[NUM_PDP_CONTEXT]; // CSD, CDMA, TRFB, CIQ + int refcount; + struct tty_struct *tty_table[1]; + struct ktermios *termios[1]; + struct ktermios *termios_locked[1]; + char tty_name[16]; + struct tty_struct *tty; + struct semaphore write_lock; + } vs_u; /* Virtual serial interface */ + } dev_u; /* App device interface */ +#define vn_dev dev_u.vnet_u +#define vs_dev dev_u.vs_u +}; + +/* +** DEBUG FEATUREs +*/ +#ifdef _DEBUG +#define _DEBUG_LOG +#define _ENABLE_ERROR_DEVICE +#endif + +#define DL_IPC 0x01<<10 +#define DL_WARN 0x01<<15 +#define DL_NOTICE 0x01<<20 +#define DL_INFO 0x01<<25 +#define DL_DEBUG 0x01<<30 + +#ifdef _DEBUG_LOG // debug printf +#define LOGE(s, args...) printk(KERN_ERR "IDPRAM/Err : <%s:%d> " s, __func__, __LINE__, ##args) // Error log +#define LOGA(s, args...) printk(KERN_INFO "IDPRAM : <%s:%d> " s, __func__, __LINE__, ##args) // Alway printed +#define LOG(s, args...) printk(KERN_INFO"IDPRAM : <%s:%d> " s, __func__, __LINE__, ##args) +#define LOGL(mask, s, args...) do{if(mask & __log_level__) printk("IDPRAM : <%s:%d> " s, __func__, __LINE__, ##args);}while(0) +#define PRINT_FUNC() printk(KERN_INFO "IDPRAM : %s() ...\n", __func__) +#else +#define LOGE(s, args...) printk("IDPRAM/Err : %s()| " s, __func__, ##args) // Error log +#define LOGA(s, args...) printk("IDPRAM : %s()| " s, __func__, ##args) // Alway printf +#define LOG(...) +#define LOGL(...) +#define PRINT_FUNC() +#endif + +#ifdef _ENABLE_ERROR_DEVICE +#define DPRAM_ERR_MSG_LEN 65 +#define DPRAM_ERR_DEVICE "dpramerr" +#define DPRAM_DUMP_DEVICE "dpram_dump" +#endif /* _ENABLE_ERROR_DEVICE */ + + +/* +** STRUCTURE DEFINITION +*/ +struct _param_em { + unsigned int offset; + unsigned char *addr; + unsigned int size; + int rw; +}; + +typedef struct dpram_serial { + struct tty_struct *tty; /* pointer to the tty for this device */ + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ +} dpram_serial_t; + +typedef struct dpram_device { + /* DPRAM memory addresses */ + unsigned long in_head_addr; + unsigned long in_tail_addr; + unsigned long in_buff_addr; + unsigned long in_buff_size; + + unsigned long out_head_addr; + unsigned long out_tail_addr; + unsigned long out_buff_addr; + unsigned long out_buff_size; + + unsigned int in_head_saved; + unsigned int in_tail_saved; + unsigned int out_head_saved; + unsigned int out_tail_saved; + + u_int16_t mask_req_ack; + u_int16_t mask_res_ack; + u_int16_t mask_send; + + dpram_serial_t serial; +} dpram_device_t; + +typedef struct dpram_tasklet_data { + dpram_device_t *device; + u_int16_t non_cmd; +} dpram_tasklet_data_t; + +struct _mem_param { + unsigned short addr; + unsigned long data; + int dir; +}; + + +/* +** Add more definitions +*/ +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 + +#ifdef CDMA_IPC_C210_IDPRAM +#define IDPRAM_WPEND_LOCK (('l'<<24) | ('o'<<16) | ('c'<<8) | 'k') +#define IDPRAM_WPEND_UNLOCK (('u'<<24) | ('n'<<16) | ('l'<<8) | 'k') +#endif + +/* +** MACRO FUNCTIONs +*/ + +#endif /* __IDPRAM_H__ */ diff --git a/drivers/dpram/raffaello/dpram_recovery.c b/drivers/dpram/raffaello/dpram_recovery.c new file mode 100644 index 0000000..3a27bf9 --- /dev/null +++ b/drivers/dpram/raffaello/dpram_recovery.c @@ -0,0 +1,1527 @@ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/irq.h> +#include <linux/poll.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/hardware.h> +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif /* CONFIG_PROC_FS */ +#include <linux/wakelock.h> +#include <linux/miscdevice.h> +#include <linux/cdev.h> +#include <linux/netdevice.h> +#include "dpram_recovery.h" +#define _DEBUG_ + +#include <mach/gpio.h> + +#ifdef _DEBUG_ +#define MSGCRIT "\x1b[1;31m" +#define MSGERR "\x1b[1;33m" +#define MSGWARN "\x1b[1;35m" +#define MSGINFO "\x1b[1;32m" +#define MSGDBG "\x1b[1;37m" + +#define MSGEND "\x1b[0m \n" +#else +#define MSGCRIT +#define MSGERR +#define MSGWARN +#define MSGINFO +#define MSGDBG +#define MSGEND +#endif + +#define DRIVER_NAME "dpram_recovery" +#define MAJOR_NUM 245 + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define MAKEWORD(a, b) ((u16)(((u8)(a)) | ((u16)((u8)(b))) << 8)) +#define MAKELONG(a, b) ((LONG)(((u16)(a)) | ((u32)((u16)(b))) << 16)) +#define LOWORD(l) ((u16)(l)) +#define HIWORD(l) ((u16)(((u32)(l) >> 16) & 0xFFFF)) +#define LOBYTE(w) ((u8)(w)) +#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF)) + +#ifdef IRQ_DPRAM_AP_INT_N +#undef IRQ_DPRAM_AP_INT_N +#endif +#define IRQ_DPRAM_AP_INT_N IRQ_MODEM_IF /* IDPRAM's special interrupt in AP */ + + +static u16 SeqIdx; +static u16 g_TotFrame; +static u16 g_CurFrame = 1; +static u16 error_code = 0x0; + + +struct dpram_dev { + int memsize; + int dpram_vbase; + struct cdev cdev; +}; + +static struct dpram_dev *dpram; +static struct dpram_firmware fw; + +#define CRC_TAB_SIZE 256 /* 2^CRC_TAB_BITS */ +#define CRC_16_L_SEED 0xFFFF + +const u16 CRC_Table[CRC_TAB_SIZE] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +static int dpram_recovery_ioremap(struct dpram_dev *dev); +static int dpram_recovery_modem_pwr_status(void); +static void dpram_recovery_modem_pwroff(void); +static int dpram_recovery_modem_pwron(void); +static u32 dpram_recovery_ReadMagicCode(void); +static u32 dpram_recovery_ReadMagicCode_fota(void); +static void dpram_recovery_WriteMagicCode(u32 dwCode); +static void dpram_recovery_WriteMagicCode_fota(u32 dwCode); +static int dpram_recovery_dpram_Init(void); +static int dpram_recovery_download_Init(void); +static u16 dpram_recovery_ReadCommand(void); +static void dpram_recovery_WriteCommand(u16 nCmd); +static u32 dpram_recovery_check_command(u16 intr, u16 mask); +static int dpram_recovery_wait_response(u16 cmd_mask); +static int dpram_recovery_WaitReadyPhase(void); +static int dpram_recovery_write_modem_firmware(struct dpram_dev *dev, char __user *firmware, int size); +static int dpram_recovery_write_modem_full_firmware(struct dpram_dev *dev, char __user *firmware, int size); +static u32 dpram_recovery_WriteImage(u8 * const pBuf, u32 dwWriteLen); +static u16 dpram_recovery_CalcTotFrame(u32 nDividend, u16 nDivisor); +static void dpram_recovery_WriteDoneRequest(void); +static int dpram_recovery_SendDonePhase(void); +static int dpram_recovery_UpdateRequestPhase(void); +static u32 dpram_recovery_DownloadControl(u8 *pBufIn, u32 Len); +static u32 dpram_recovery_DownloadControl_fullfirmware(u8 *pBufIn, u32 Len); +static u32 dpram_recovery_StatusNotiPhase(u32 *pPercent, u8 *UpDoneNotiFlag); +static u32 dpram_recovery_StatusNotiPhase_download(u32 *pPercent, u8 *UpDoneNotiFlag); +static int dpram_recovery_check_status(struct dpram_dev *dev, int __user *pct); +static int dpram_recovery_check_status_download(struct dpram_dev *dev, int __user *pct); +static int register_interrupt_handler(void); + +typedef struct Up_Noti { + u16 Bop; + u16 progress_status; + u16 error_code; + u16 Eop; +} Status_UpNoti, *pStatus_UpNoti; + +typedef struct Up_Notification { + u16 Bop; + u16 Region; + u16 Percent; + u16 Eop; +} Check_UpNoti; + +static int +__inline __writel_once(struct dpram_dev *dev, int addr, int data) +{ + *(int *)(dev->dpram_vbase+addr) = data; + + return 0; +} + +static int +dpram_recovery_ioremap(struct dpram_dev *dev) +{ + int i; + + /*Clock Settings for Modem IF ====>FixMe */ + u32 val; + void __iomem *regs = ioremap(0x10030000, 0x10000); + + printk(MSGDBG "%s" MSGEND, __func__); + /*Enabling Clock for ModemIF in Reg CLK_GATE_IP_PERIL:0x1003C950 */ + val = readl(regs + 0xC950); + val |= 0x10000000; + writel(val, regs + 0xC950); + iounmap(regs); + + dev->dpram_vbase = (int)ioremap_nocache(DPRAM_BASE_ADDR, DPRAM_SIZE); + + if (dev->dpram_vbase == 0) { + printk("failed ioremap\n"); + return -ENOENT; + } + + printk(KERN_DEBUG "dpram vbase=0x%8x\n", dev->dpram_vbase); + + dev->memsize = DPRAM_SIZE; + + printk(MSGDBG " dpram_vbase = 0x%08x" MSGEND, dev->dpram_vbase); + printk(MSGDBG " memsize = 0x%08x" MSGEND, dev->memsize); + + for (i = 0; i < DPRAM_SIZE; i = i+4) { + if (__writel_once(dev, i, 0xffffffff)) { + printk(KERN_DEBUG "Exit during dpram initialization.\n"); + return 0; + } + } + + return 0; +} + +static int +dpram_recovery_modem_pwr_status(void) +{ + printk(KERN_ERR "%s Modem Active: %d\n", __func__, gpio_get_value(GPIO_QSC_PHONE_ACTIVE)); + + return gpio_get_value(GPIO_QSC_PHONE_ACTIVE); +} + +static void +dpram_recovery_modem_pwroff(void) +{ + int phone_wait_cnt = 0; + + printk(KERN_ERR "%s\n", __func__); + + /* phone power off */ + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + + /* confirm phone off */ + while (1) { + if (gpio_get_value(GPIO_QSC_PHONE_ACTIVE)) { + printk(KERN_ALERT"%s: Try to Turn Phone Off by CP_RST\n", __func__); + gpio_set_value(GPIO_QSC_PHONE_RST, 0); + if (phone_wait_cnt > 1) { + printk(KERN_ALERT "%s: PHONE OFF Failed\n", __func__); + break; + } + phone_wait_cnt++; + mdelay(1000); + } else { + printk(KERN_ALERT "%s: PHONE OFF Success\n", __func__); + break; + } + } + +} + +static int +dpram_recovery_modem_pwron(void) +{ + printk(KERN_ERR "%s\n", __func__); + + gpio_direction_output(GPIO_QSC_PHONE_RST, GPIO_LEVEL_HIGH); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + msleep(100); + + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_HIGH); + msleep(400); + msleep(400); + msleep(200); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW); + + + return 1; +} + +static u32 +dpram_recovery_ReadMagicCode(void) +{ + u32 dwCode; + u32 *dwMagicCodeAddress; + + dwMagicCodeAddress = (u32 *)(dpram->dpram_vbase); + memcpy((void *)&dwCode, (void *)(dwMagicCodeAddress), 4); + + return dwCode; +} + +static void +dpram_recovery_WriteMagicCode(u32 dwCode) +{ + u32 *dwMagicCodeAddress; + dwMagicCodeAddress = (u32 *)(dpram->dpram_vbase); + + SeqIdx = 1; + memcpy((void *)dwMagicCodeAddress, (void *)&dwCode, 4); +} + +static u32 +dpram_recovery_ReadMagicCode_fota(void) +{ + u32 dwCode; + u32 *dwMagicCodeAddress; + + dwMagicCodeAddress = (u32 *)(dpram->dpram_vbase); + memcpy((void *)&dwCode, (void *)(dwMagicCodeAddress + 1), 4); + + return dwCode; +} + +static void +dpram_recovery_WriteMagicCode_fota(u32 dwCode) +{ + u32 *dwMagicCodeAddress; + dwMagicCodeAddress = (u32 *)(dpram->dpram_vbase); + + SeqIdx = 1; + memcpy((void *)(dwMagicCodeAddress + 1), (void *)&dwCode, 4); +} + + +static int +dpram_recovery_dpram_Init(void) +{ + const u32 dwMagicCodeToWrite = MAGIC_FODN; + const u32 dwMagicCodeToWrite_fota = MAGIC_FOTA; + u32 dwMagicCode = 0; + u32 dwMagicCode_fota = 0; + int iRetry = 0, nCnt = 0; + + printk(KERN_DEBUG "+DPRAM_Init\n"); + + /* Write the magic code */ + for (iRetry = 1; iRetry > 0 ; iRetry--) { + dwMagicCode = dpram_recovery_ReadMagicCode(); + + if (dwMagicCode == dwMagicCodeToWrite) { + printk(KERN_DEBUG "dwMagicCode == dwMagicCodeToWrite!!\n"); + break; + } + dpram_recovery_WriteMagicCode(dwMagicCodeToWrite); + + dwMagicCode = dpram_recovery_ReadMagicCode(); + printk("\n #### magic code: %x\n", dwMagicCode); + } + + for (iRetry = 1; iRetry > 0 ; iRetry--) { + + dwMagicCode_fota = dpram_recovery_ReadMagicCode_fota(); + + if (dwMagicCode_fota == dwMagicCodeToWrite_fota) { + printk(KERN_DEBUG "dwMagicCode_fota == dwMagicCodeToWrite_fota!!\n"); + break; + } + dpram_recovery_WriteMagicCode_fota(dwMagicCodeToWrite_fota); + + dwMagicCode_fota = dpram_recovery_ReadMagicCode_fota(); + printk("\n ### magic code for FOTA: %x\n", dwMagicCode_fota); + } + + dpram_recovery_modem_pwron(); + + /* Check phone on status */ + while (!dpram_recovery_modem_pwr_status()) { + msleep(1000); + nCnt++; + if (nCnt >= 20) { + printk(KERN_DEBUG "no phone active!! \n"); + return FALSE; + } + } + /* added one second delay after phone on */ + mdelay(1000); + printk(KERN_DEBUG "Phone Active!!!\n"); + printk(KERN_DEBUG "-DPRAM_Init\n"); + return TRUE; +} + +/* download */ +static int +dpram_recovery_download_Init(void) +{ + const u32 dwMagicCodeToWrite = MAGIC_DMDL; + u32 dwMagicCode = 0; + int iRetry = 0, nCnt = 0; + + printk(KERN_DEBUG "+DPRAM_Init\n"); + + /* Write the magic code */ + for (iRetry = 1; iRetry > 0 ; iRetry--) { + dwMagicCode = dpram_recovery_ReadMagicCode(); + + if (dwMagicCode == dwMagicCodeToWrite) { + printk(KERN_DEBUG "dwMagicCode == dwMagicCodeToWrite!!\n"); + break; + } + dpram_recovery_WriteMagicCode(dwMagicCodeToWrite); + + dwMagicCode = dpram_recovery_ReadMagicCode(); + printk("\n #### magic code: %x\n", dwMagicCode); + } + + dpram_recovery_modem_pwron(); + + /* Check phone on status */ + while (!dpram_recovery_modem_pwr_status()) { + msleep(1000); + nCnt++; + if (nCnt >= 20) { + printk(KERN_DEBUG "no phone active!! \n"); + return FALSE; + } + } + mdelay(1000); + printk(KERN_DEBUG "Phone Active!!!\n"); + printk(KERN_DEBUG "-DPRAM_Init\n"); + return TRUE; +} + +/* download */ +static u16 +dpram_recovery_ReadCommand(void) +{ + u16 nCmd = 0; + + memcpy((void *)&nCmd, (void *)(dpram->dpram_vbase + DPRAM_PHONE2PDA_INTERRUPT_ADDRESS), 2); + + return nCmd; +} + +static void +dpram_recovery_clear_modem_command(void) +{ + u16 clear; + clear = 0x0000; + + printk(KERN_DEBUG "dpram_recovery_clear_modem_command\n"); + + memcpy((void *)(dpram->dpram_vbase + DPRAM_PHONE2PDA_INTERRUPT_ADDRESS), (void *)&clear, 2); +} + +static void +dpram_recovery_WriteCommand(u16 nCmd) +{ + printk(KERN_DEBUG "\n\n ###[DPRAM_WriteCommand] Start : 0x%04x \n\n", nCmd); + + dpram_recovery_clear_modem_command(); + + memcpy((void *)(dpram->dpram_vbase + DPRAM_PDA2PHONE_INTERRUPT_ADDRESS), (void *)&nCmd, 2); +} + +static u32 +dpram_recovery_check_command(u16 intr, u16 mask) +{ + /* There's no Interrupt from Phone. we have to poll again.*/ + if (intr == 0) { + return CMD_RETRY; + } + /* Some command arrived.*/ + else { + if ((intr & MASK_CMD_VALID) != MASK_CMD_VALID) + return CMD_RETRY; + + else if ((intr & MASK_PDA_CMD) == MASK_PDA_CMD) + return CMD_RETRY; + + else if ((intr & MASK_PHONE_CMD) == MASK_PHONE_CMD) { + if ((intr & mask) == mask) + return CMD_TRUE; + + else + return CMD_FALSE; + + } else + return CMD_RETRY; + + } +} + +static int +dpram_recovery_wait_response(u16 cmd_mask) +{ + u16 intr; + int nRetry = 0; + int ret = 0; + + while (1) { + if (nRetry > 100) + return FALSE; + + intr = dpram_recovery_ReadCommand(); + printk(KERN_DEBUG "intr = 0x%x\n", intr); + + ret = dpram_recovery_check_command(intr, cmd_mask); + if (ret == CMD_TRUE) { + printk(KERN_DEBUG "READY ok\n"); + return TRUE; + } else if (ret == CMD_FALSE) { + printk(KERN_DEBUG "READY failed.\n"); + return FALSE; + } + + nRetry++; + if (fw.image_type == DPRAM_MODEM_DELTA_IMAGE) + msleep(1000); + else + msleep(5); + + } + + return TRUE; +} + +static int +dpram_recovery_WaitReadyPhase(void) +{ + int retval = TRUE; + + /* Send Delta Image Receive Ready Request */ + printk("Writing command for modem \n"); + dpram_recovery_WriteCommand(CMD_FOTA_IMG_RECEIVE_READY_REQ); + + /* Wait Delta Image Receive Ready Response */ + printk("Waiting for the response from Modem \n"); + retval = dpram_recovery_wait_response(MASK_CMD_FOTA_IMG_RECEIVE_READY_RESP); + + return retval; +} + +static int +dpram_recovery_WaitReadyPhase_download(void) +{ + int retval = TRUE; + + /* Send Delta Image Receive Ready Request */ + printk("Writing command for modem \n"); + dpram_recovery_WriteCommand(CMD_FOTA_IMG_SEND_REQ); + + /* Wait Delta Image Receive Ready Response */ + printk("Waiting for the response from Modem \n"); + retval = dpram_recovery_wait_response(MASK_CMD_FOTA_SEND_DONE_RESP | MASK_CMD_RESULT_SUCCESS); + + return retval; +} + +static int +dpram_recovery_write_modem_firmware( + struct dpram_dev *dev, char __user *firmware, int size) +{ + int ret = FALSE; + + /* Start Wait Ready Phase */ + if (dpram_recovery_WaitReadyPhase() == FALSE) { + printk(" error[-2] in return %s \n", __func__); + ret = -2; + goto Exit; + } + + /* Downlaod start Req ~ Update Status Noti */ + ret = dpram_recovery_DownloadControl((u8 *)firmware, size); + if (ret < 0) { + printk(KERN_DEBUG "[DPRAM_Download]Failed in DownloadControl\n."); + goto Exit; + } + printk(KERN_DEBUG "[DPRAM_Download]FileSize : %d\n", size); + printk(KERN_DEBUG "[DPRAM_Download]Bootloader Image Download Completed!\n"); + + if (!dpram_recovery_UpdateRequestPhase()) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] Wait FOTA Update Start Response Failed!!\n"); + ret = -7; /* -7 means that FOTA Update Start Response failed. */ + goto Exit; + } + + ret = TRUE; + +Exit: + return ret; +} + +static int +dpram_recovery_write_modem_full_firmware(struct dpram_dev *dev, char __user *firmware, int size) +{ + int ret = FALSE; + + /* Start Wait Ready Phase */ + if (dpram_recovery_wait_response(MASK_CMD_FOTA_IMG_RECEIVE_READY_RESP) == FALSE) { + printk(" error[-2] in return %s \n", __func__); + ret = -2; + goto Exit; + } + + /* Clear Response */ + dpram_recovery_clear_modem_command(); + + /* Downlaod start Req ~ Update Status Noti */ + ret = dpram_recovery_DownloadControl_fullfirmware((u8 *)firmware, size); + if (ret < 0) { + printk(KERN_DEBUG "[DPRAM_Download]Failed in DownloadControl\n."); + goto Exit; + } + printk(KERN_DEBUG "[DPRAM_Download]FileSize : %d\n", size); + printk(KERN_DEBUG "[DPRAM_Download]Bootloader Image Download Completed!\n"); + + ret = TRUE; + +Exit: + return ret; +} + +static u16 +dpram_recovery_MakeCRC(u16 length, u16 *data_ptr_WORD) +{ + u16 data_crc = CRC_16_L_SEED; + u16 const *table = CRC_Table; + u8 *data_ptr = (u8 *)data_ptr_WORD; + int i; + + for (i = 0; i < length; i++) { + data_crc = (((data_crc) >> 8) ^ table[((data_crc) ^ (u16)(data_ptr[i])) & 0x00ff]); + /*printk(KERN_DEBUG "%010d:0x%04x\r\n", i, data_crc ); */ + } + /*printk(KERN_DEBUG "[MakeCRC] length:%d pt:0x%08x i:%d v:0x%04x \r\n", length, data_ptr, i, data_ptr[i] ); */ + return data_crc; +} + +static u32 +dpram_recovery_WriteImage(u8 *const pBuf, u32 dwWriteLen) +{ + u8 *pDest; + u8 *pDest_Data; + u16 Len; + u16 nCrc; + + /*printk(KERN_DEBUG "Start %d 0x%04x(%d)\n", dwWriteLen, g_TotFrame, g_TotFrame);*/ + + pDest = (u8 *)(dpram->dpram_vbase + DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS); + Len = (u16)min((u32)dwWriteLen, (u32)FODN_DEFAULT_WRITE_LEN); + + /*printk(KERN_DEBUG "Start : pDest(0x%08x), dwWriteLen(%d)\n",pDest, Len);*/ + + /* Start Index */ + *pDest++ = LOBYTE(START_INDEX); + *pDest++ = HIBYTE(START_INDEX); + + /*Total Frame number: */ + *pDest++ = LOBYTE(g_TotFrame); + *pDest++ = HIBYTE(g_TotFrame); + + /*Current Frame number; */ + *pDest++ = LOBYTE(g_CurFrame); + *pDest++ = HIBYTE(g_CurFrame); + g_CurFrame++; + + /* Length - Does it include the length of START_INDEX?? */ + *pDest++ = LOBYTE(Len); + *pDest++ = HIBYTE(Len); + + /* Data */ + pDest_Data = pDest; + memcpy((void *)pDest, (void *)pBuf, Len); + pDest += Len; + + /* Fill null if data length is odd */ + if (Len%2 != 0) { + *pDest++ = 0xff; + printk(KERN_DEBUG "odd 0x%08x 0x%02x\n", (unsigned int)(pDest-1), (u8)(*pDest-1)); + } + + /*printk(KERN_DEBUG "len:%d default len:%d\n", Len, FODN_DEFAULT_WRITE_LEN);*/ + /*printk(KERN_DEBUG "start data 0x%08x \n", pDest);*/ + + if (Len < FODN_DEFAULT_WRITE_LEN) { + memset((void *)pDest, 0x0 /*0xff*/, FODN_DEFAULT_WRITE_LEN - Len); + pDest += (FODN_DEFAULT_WRITE_LEN - Len) ; + } + printk(KERN_DEBUG "CRC start 0x%08x\n", (unsigned int)pDest); + + nCrc = dpram_recovery_MakeCRC(Len, (u16 *)pDest_Data); + + *pDest++ = LOBYTE(nCrc); + *pDest++ = HIBYTE(nCrc); + + printk(KERN_DEBUG "CRC value 0x%04x \n", nCrc); + + *pDest++ = LOBYTE(END_INDEX); + *pDest++ = HIBYTE(END_INDEX); + + /* Write Command*/ + dpram_recovery_WriteCommand(CMD_FOTA_IMG_SEND_REQ); + + return Len; +} + +static u32 +dpram_recovery_WriteImage_download(u8 *const pBuf, u32 dwWriteLen) +{ + u8 *pDest; + u8 *pDest_Data; + u16 Len; + u16 nCrc; + + /*printk(KERN_DEBUG "Start %d 0x%04x(%d)\n", dwWriteLen, g_TotFrame, g_TotFrame);*/ + + pDest = (u8 *)(dpram->dpram_vbase + DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS); + Len = (u16)min((u32)dwWriteLen, (u32)FODN_DEFAULT_WRITE_LEN); + + /*printk(KERN_DEBUG "Start : pDest(0x%08x), dwWriteLen(%d)\n",pDest, Len);*/ + + /* Start Index */ + *pDest++ = LOBYTE(START_INDEX); + *pDest++ = HIBYTE(START_INDEX); + + /*Total Frame number: */ + *pDest++ = LOBYTE(g_TotFrame); + *pDest++ = HIBYTE(g_TotFrame); + + /*Current Frame number; */ + *pDest++ = LOBYTE(g_CurFrame); + *pDest++ = HIBYTE(g_CurFrame); + g_CurFrame++; + + /* Length - Does it include the length of START_INDEX?? */ + *pDest++ = LOBYTE(Len); + *pDest++ = HIBYTE(Len); + + /* Data */ + pDest_Data = pDest; + memcpy((void *)pDest, (void *)pBuf, Len); + pDest += Len; + + /* Fill null if data length is odd */ + if (Len%2 != 0) { + *pDest++ = 0xff; + printk(KERN_DEBUG "odd 0x%08x 0x%02x\n", (unsigned int)(pDest-1), (u8)(*pDest-1)); + } + + /*printk(KERN_DEBUG "len:%d default len:%d\n", Len, FODN_DEFAULT_WRITE_LEN);*/ + /*printk(KERN_DEBUG "start data 0x%08x \n", pDest);*/ + + if (Len < FODN_DEFAULT_WRITE_LEN) { + memset((void *)pDest, 0x0 /*0xff*/, FODN_DEFAULT_WRITE_LEN - Len); + pDest += (FODN_DEFAULT_WRITE_LEN - Len) ; + } + printk(KERN_DEBUG "CRC start 0x%08x\n", (unsigned int)pDest); + + nCrc = dpram_recovery_MakeCRC(Len, (u16 *)pDest_Data); + + *pDest++ = LOBYTE(nCrc); + *pDest++ = HIBYTE(nCrc); + + printk(KERN_DEBUG "CRC value 0x%04x \n", nCrc); + + pDest = (u8 *)(dpram->dpram_vbase + BSP_DPRAM_BASE_SIZE - 2*DPRAM_INTERRUPT_SIZE - DPRAM_INDEX_SIZE); + + *pDest++ = LOBYTE(END_INDEX); + *pDest++ = HIBYTE(END_INDEX); + + /* Write Command*/ + dpram_recovery_WriteCommand(CMD_FOTA_UPDATE_START_REQ); + + return Len; +} + + +static u16 +dpram_recovery_CalcTotFrame(u32 nDividend, u16 nDivisor) +{ + u16 nCompVal1 = 0; + u16 nCompVal2 = 0; + + printk(KERN_DEBUG "[CalcTotFrame](%d) %d %d\n", __LINE__, nDividend, nDivisor); + nCompVal1 = (u16) (nDividend / nDivisor); + nCompVal2 = (u16) (nDividend - (nCompVal1 * nDivisor)); + if (nCompVal2 > 0) { + printk(KERN_DEBUG "[CalcTotFrame](%d) val2 : %d\n", __LINE__, nCompVal2); + nCompVal1++; + } + printk(KERN_DEBUG "[CalcTotFrame](%d) result %d\n", __LINE__, nCompVal1); + return nCompVal1; +} + +static void +dpram_recovery_WriteDoneRequest(void) +{ + printk(KERN_DEBUG "[DPRAM_WriteDoneRequest] Start\n"); + + SeqIdx = 1; + + dpram_recovery_WriteCommand(CMD_FOTA_SEND_DONE_REQ); + printk(KERN_DEBUG "[DPRAM_WriteDoneRequest] End\n"); +} + +static int +dpram_recovery_SendDonePhase(void) +{ + int retval = TRUE; + + /* Send Write Done Request */ + dpram_recovery_WriteDoneRequest(); + + /* Wait Write Done Response */ + retval = dpram_recovery_wait_response(MASK_CMD_FOTA_SEND_DONE_RESP); + if (retval == FALSE) { + printk(KERN_DEBUG " Wait Write Done Response Failed!!\n"); + return retval; + } + + printk(KERN_DEBUG "Wait 0.5 secs.. .. ..\n"); + msleep(500); + + return retval; +} + +static int +dpram_recovery_UpdateRequestPhase(void) +{ + int retval = TRUE; + + /* Send FOTA Update Start Request */ + dpram_recovery_WriteCommand(CMD_FOTA_UPDATE_START_REQ); + /* Wait FOTA Update Start Response */ + /*retval = dpram_recovery_wait_response(MASK_CMD_FOTA_UPDATE_START_RESP); */ + + return retval; +} + +static u32 +dpram_recovery_DownloadControl(u8 *pBufIn, u32 Len) +{ + u32 dwWriteLen = 0, dwWrittenLen = 0, dwTotWrittenLen = 0; + u32 dwRet = 0; + u16 nTotalFrame = 0, nIntrValue = 0; + int nwRetry = 0, nrRetry = 0, retval; + + nTotalFrame = dpram_recovery_CalcTotFrame(Len, DELTA_PACKET_SIZE); + g_TotFrame = nTotalFrame; + printk(KERN_DEBUG "[DPRAM_DownloadControl] total frame:%d,%d\n", g_TotFrame, nTotalFrame); + + while (dwTotWrittenLen < Len) { + /*Write proper size of image to DPRAM*/ + printk(KERN_DEBUG "[DPRAM_DownloadControl]DPRAM_WriteImage %d/%d start\n", + g_CurFrame, g_TotFrame); + dwWriteLen = min((u32)(Len - dwTotWrittenLen), (u32)DELTA_PACKET_SIZE); + dwWrittenLen = dpram_recovery_WriteImage(pBufIn, dwWriteLen); + printk(KERN_DEBUG "[DPRAM_DownloadControl]Written data:%d\n", dwWrittenLen); + + if (dwWrittenLen > 0) { + dwTotWrittenLen += dwWrittenLen; + pBufIn += dwWrittenLen; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl]Write Image Len is wierd.\n"); + if (nwRetry < 3) { + nwRetry++; + printk(KERN_DEBUG "[DPRAM_DownloadControl]Retry to write. nRetry = %8x\n", nwRetry); + continue; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl]Fail to Write Image to DPRAM.\n"); + dwRet = -3; + goto Exit; + } + } + + /* Wait for the IMAGE WRITE RESPONSE */ + while (nrRetry < 10) { + retval = dpram_recovery_wait_response(MASK_CMD_FOTA_IMG_SEND_RESP); + if (retval == FALSE) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] Wait Image Send Response Failed\n"); + dwRet = -4; + goto Exit; + } else { + nIntrValue = dpram_recovery_ReadCommand(); + if ((nIntrValue & MASK_CMD_RESULT_FAIL) == 0) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] MASK_CMD_IMAGE_SEND_RESPONSE OK issued.\n"); + printk(KERN_DEBUG "[DPRAM_DownloadControl] %d /%d ok\n", g_CurFrame - 1, g_TotFrame); + break; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl] MASK_CMD_IMAGE_SEND_RESPONSE Failed issued.\n"); + msleep(100); + nrRetry++; + dpram_recovery_WriteCommand(CMD_FOTA_IMG_SEND_REQ); + printk(KERN_DEBUG "[DPRAM_DownloadControl] CMD_IMG_SEND_REQ retry.(%d)\n", nrRetry); + + if (nrRetry >= 10) { + dwRet = -5; + goto Exit; + } + } + } + } + } + + g_CurFrame = 1; + + if (!dpram_recovery_SendDonePhase()) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] There's something unexpeted in SendDone Phase.\n"); + dwRet = -6; /* -6 means that SendDone Phase failed. */ + goto Exit; + } + +Exit: + return dwRet; +} + +static u32 +dpram_recovery_DownloadControl_fullfirmware(u8 *pBufIn, u32 Len) +{ + u32 dwWriteLen = 0, dwWrittenLen = 0, dwTotWrittenLen = 0; + u32 dwRet = 0; + u16 nTotalFrame = 0, nIntrValue = 0; + int nwRetry = 0, nrRetry = 0, retval; + + /* Send command and wait for response */ + if (dpram_recovery_WaitReadyPhase_download() == FALSE) { + printk(" error[-2] in return %s \n", __func__); + dwRet = -2; + goto Exit; + } + + nTotalFrame = dpram_recovery_CalcTotFrame(Len, FODN_DEFAULT_WRITE_LEN); + g_TotFrame = nTotalFrame; + printk(KERN_DEBUG "[DPRAM_DownloadControl] total frame:%d\n", nTotalFrame); + + while (dwTotWrittenLen < Len) { + /*Write proper size of image to DPRAM*/ + printk(KERN_DEBUG "[DPRAM_DownloadControl]DPRAM_WriteImage %d/%d start\n", + g_CurFrame, g_TotFrame); + dwWriteLen = min((u32)(Len - dwTotWrittenLen), (u32)FODN_DEFAULT_WRITE_LEN); + dwWrittenLen = dpram_recovery_WriteImage_download(pBufIn, dwWriteLen); + printk(KERN_DEBUG "[DPRAM_DownloadControl]Written data:%d\n", dwWrittenLen); + + if (dwWrittenLen > 0) { + dwTotWrittenLen += dwWrittenLen; + pBufIn += dwWrittenLen; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl]Write Image Len is wierd.\n"); + if (nwRetry < 3) { + nwRetry++; + printk(KERN_DEBUG "[DPRAM_DownloadControl]Retry to write. nRetry = %8x\n", nwRetry); + continue; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl]Fail to Write Image to DPRAM.\n"); + dwRet = -3; + goto Exit; + } + } + + /* Wait for the IMAGE WRITE RESPONSE */ + while (nrRetry < 10) { + retval = dpram_recovery_wait_response(MASK_CMD_IMAGE_SEND_RESPONSE); + if (retval == FALSE) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] Wait Image Send Response Failed\n"); + dwRet = -4; + goto Exit; + } else { + nIntrValue = dpram_recovery_ReadCommand(); + if ((nIntrValue & MASK_CMD_RESULT_FAIL) == 0) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] MASK_CMD_IMAGE_SEND_RESPONSE OK issued.\n"); + printk(KERN_DEBUG "[DPRAM_DownloadControl] %d /%d ok\n", g_CurFrame - 1, g_TotFrame); + break; + } else { + printk(KERN_DEBUG "[DPRAM_DownloadControl] MASK_CMD_IMAGE_SEND_RESPONSE Failed issued.\n"); + msleep(100); + nrRetry++; + dpram_recovery_WriteCommand(CMD_FOTA_UPDATE_START_REQ); + printk(KERN_DEBUG "[DPRAM_DownloadControl] CMD_IMG_SEND_REQ retry.(%d)\n", nrRetry); + + if (nrRetry >= 10) { + dwRet = -5; + goto Exit; + } + } + } + } + } + + g_CurFrame = 1; + + /* SendDone Phase */ + dpram_recovery_WriteCommand(CMD_DL_SEND_DONE_REQ); + printk(KERN_DEBUG "[DPRAM_WriteDoneRequest] End\n"); + + printk(KERN_DEBUG "Wait 0.5 secs.. .. ..\n"); + msleep(500); + + +Exit: + return dwRet; +} + +static u32 +dpram_recovery_StatusNotiPhase(u32 *pPercent, u8 *UpDoneNotiFlag) +{ + Status_UpNoti UpStatus; + u16 intr = 0, ret = 0; + u32 dwRet = TRUE; + + UpStatus.progress_status = 0x00; + UpStatus.error_code = 0x00; + + *UpDoneNotiFlag = FALSE; + + /*dpram_recovery_WriteCommand(CMD_FOTA_UPDATE_STATUS_IND); */ + + /* Wait FOTA Update Status Indication */ + dwRet = dpram_recovery_wait_response(MASK_CMD_FOTA_UPDATE_STATUS_IND); + if (dwRet == FALSE) { + printk(KERN_DEBUG "Wait FOTA Update Status Indication Failed!!\n"); + intr = dpram_recovery_ReadCommand(); + ret = dpram_recovery_check_command(intr, MASK_CMD_FOTA_UPDATE_END_IND); + if (ret == CMD_TRUE) { + dwRet = TRUE; + *UpDoneNotiFlag = TRUE; + printk(KERN_DEBUG "But FOTA Update Done Indication Received!!\n"); + goto StatusRead; + } else + goto Exit; + } + +StatusRead: + memcpy((void *)&UpStatus, (void *)(dpram->dpram_vbase + DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS), 8); + + printk(KERN_DEBUG "0x%x 0x%x 0x%x 0x%x \n", UpStatus.Bop, UpStatus.progress_status, UpStatus.error_code, UpStatus.Eop); + + if ((UpStatus.Bop != START_INDEX) || (UpStatus.Eop != END_INDEX)) { + printk(KERN_DEBUG "Packet format is wrong.\n"); + dwRet = 0; + } else { + printk(KERN_DEBUG "Get the Status info.\n"); + *pPercent = (u32)UpStatus.progress_status; + error_code = (u16)UpStatus.error_code; + } + + if (error_code != 0) { + printk(KERN_DEBUG "Update error is occured, error number:0x%x.\n", error_code); + dwRet = FALSE; + goto Exit; + } + +Exit: + /* Clear modem command for next IOCTL_CHK_STAT */ + dpram_recovery_clear_modem_command(); + + return dwRet; +} + +static u32 +dpram_recovery_StatusNotiPhase_download(u32 *pPercent, u8 *UpDoneNotiFlag) +{ + Check_UpNoti upstatus; + u16 ret = 0; + u32 dwRet = TRUE; + + upstatus.Region = 0x0; + upstatus.Percent = 0x0; + + *UpDoneNotiFlag = FALSE; + + dwRet = dpram_recovery_wait_response(MASK_CMD_UPDATE_DONE_NOTIFICATION|MASK_CMD_RESULT_SUCCESS); + if (dwRet == FALSE) { + dwRet = dpram_recovery_wait_response(MASK_CMD_STATUS_UPDATE_NOTIFICATION|MASK_CMD_RESULT_SUCCESS); + if (dwRet == TRUE) { + printk(KERN_DEBUG "Received UPDATE Status Notification Command in %s", __func__); + goto StatusRead; + } else { + ret = FALSE; + goto Exit; + } + } else { + printk(KERN_DEBUG " Successfully Received UPDATE DONE Command in %s", __func__); + *UpDoneNotiFlag = TRUE; + ret = TRUE; + goto StatusRead; + } + +StatusRead: + dpram_recovery_clear_modem_command(); + memcpy((void *)&upstatus, (void *)(dpram->dpram_vbase + DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS), 8); + if ((upstatus.Bop != START_INDEX) || (upstatus.Eop != END_INDEX)) { + printk(KERN_DEBUG "CP Update Failed by Bad Header!! \n"); + printk(KERN_DEBUG "0x%x 0x%x \n", upstatus.Bop, upstatus.Eop); + ret = FALSE; + goto Exit; + } else { + *pPercent = upstatus.Percent; + printk(KERN_DEBUG "Region= 0x%x Percent = 0x%x \n", upstatus.Region, upstatus.Percent); + ret = TRUE; + } +Exit: + /* Clear modem command for next IOCTL_CHK_STAT */ + dpram_recovery_clear_modem_command(); + return ret; + +} + +static int +dpram_recovery_check_status(struct dpram_dev *dev, int __user *pct) +{ + u32 bUpStatusPer = 0, PrevbUpStatusPer = 0; + u8 UpDoneNotiFlag = 0; + u32 dwRet = 1; + int retval = 0; + + /* Process for UPDATE STATUS Noti. phase. */ + retval = dpram_recovery_StatusNotiPhase(&bUpStatusPer, &UpDoneNotiFlag); + if (retval == FALSE) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] Wait Status Noti Phase Failed!!\n"); + dwRet = -8; + } else { + printk(KERN_DEBUG "Progress:%d\n", bUpStatusPer); + + if (bUpStatusPer > PrevbUpStatusPer) + PrevbUpStatusPer = bUpStatusPer; + + *pct = bUpStatusPer; + + if ((bUpStatusPer == 100) && (UpDoneNotiFlag == TRUE)) { + printk(KERN_DEBUG "Done!!!\n"); + dwRet = 0; + } + } + + return dwRet; +} + +static int +dpram_recovery_check_status_download(struct dpram_dev *dev, int __user *pct) +{ + u32 bUpStatusPer = 0, PrevbUpStatusPer = 0; + u8 UpDoneNotiFlag = 0; + u32 dwRet = 1; + int retval = 0; + + /* Process for UPDATE STATUS Noti. phase. */ + retval = dpram_recovery_StatusNotiPhase_download(&bUpStatusPer, &UpDoneNotiFlag); + if (retval == FALSE) { + printk(KERN_DEBUG "[DPRAM_DownloadControl] Wait Status Noti Phase Failed!!\n"); + dwRet = -8; + } else { + printk(KERN_DEBUG "Progress:%d\n", bUpStatusPer); + + if (bUpStatusPer > PrevbUpStatusPer) + PrevbUpStatusPer = bUpStatusPer; + + *pct = bUpStatusPer; + + if ((bUpStatusPer == 100) && (UpDoneNotiFlag == TRUE)) { + printk(KERN_DEBUG "Done!!!\n"); + dwRet = 0; + } + } + + return dwRet; +} + +static ssize_t +dpram_recovery_read(struct file *filp, char __user *buff, + size_t count, loff_t *fpos) +{ + return 0; +} + +static ssize_t +dpram_recovery_write(struct file *filp, const char __user *buff, + size_t size, loff_t *fpos) +{ + return 0; +} + +static long +dpram_recovery_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) + +{ + struct dpram_dev *dev; + int ret = 0, ret_check = 0; + u32 magic_code = 0x0; + + printk(MSGDBG "%s" MSGEND, __func__); + printk(KERN_ERR "%s\n", __func__); + + dev = container_of(filp->f_path.dentry->d_inode->i_cdev, struct dpram_dev, cdev); + + switch (cmd) { + case IOCTL_WRITE_MAGIC_CODE: + dpram_recovery_dpram_Init(); + break; + + case IOCTL_ST_FW_UPDATE: + printk(KERN_ERR "%s IOCTL_ST_FW_UPDATE\n", __func__); + + if (arg == 0) { + printk(MSGWARN "Firmware should be written prior to this call" MSGEND); + } else { + ret_check = copy_from_user((void *)&fw, (void *)arg, sizeof(fw)); + if (ret_check) { + printk("[IOCTL_ST_FW_UPDATE]copy from user failed!"); + return -EFAULT; + } + } + + /* Dpram Phone off */ + dpram_recovery_modem_pwroff(); + if (fw.image_type == DPRAM_MODEM_DELTA_IMAGE) { + /* Enter FOTA Update Mode */ + dpram_recovery_dpram_Init(); + ret = dpram_recovery_write_modem_firmware(dev, fw.firmware, fw.size); + if (ret < 0) { + printk("firmware write failed\n"); + } + + } else { + /* Enter Download Mode */ + dpram_recovery_download_Init(); + ret = dpram_recovery_write_modem_full_firmware(dev, fw.firmware, fw.size); + if (ret < 0) { + printk("firmware write failed\n"); + } + } + break; + case IOCTL_CHK_STAT: + { + struct stat_info *pst; + + printk(KERN_ERR "%s IOCTL_CHK_STAT\n", __func__); + pst = (struct stat_info *)arg; + if (fw.image_type == DPRAM_MODEM_DELTA_IMAGE) { + ret = dpram_recovery_check_status(dev, &(pst->pct)); + } else { + ret = dpram_recovery_check_status_download(dev, &(pst->pct)); + } + } + break; + + case IOCTL_MOD_PWROFF: + printk(KERN_ERR "%s IOCTL_MOD_PWROFF\n", __func__); + + msleep(2000); /* Delay for display */ + + /* Clear Magic Code */ + dpram_recovery_WriteMagicCode(magic_code); + + dpram_recovery_modem_pwroff(); + break; + + default: + printk(KERN_ERR "Unknown command"); + break; + } + + return ret; +} + +static int +dpram_recovery_open(struct inode *inode, struct file *filp) +{ + struct dpram_dev *dev; + + printk(KERN_ERR "%s\n", __func__); + + dev = container_of(inode->i_cdev, struct dpram_dev, cdev); + filp->private_data = (void *)dev; + + return 0; +} + +static int +dpram_recovery_release(struct inode *inode, struct file *filp) +{ + printk(KERN_DEBUG "dpram recovery device released.\n"); + return 0; +} + + +static struct file_operations dpram_recovery_fops = { + .owner = THIS_MODULE, + .read = dpram_recovery_read, + .write = dpram_recovery_write, + .unlocked_ioctl = dpram_recovery_ioctl, + .open = dpram_recovery_open, + .release = dpram_recovery_release, +}; + +static int register_dpram_rec_device(void) +{ + struct device *dpram_rec_dev_t; + struct class *dpram_rec_class; + int ret; + + ret = register_chrdev(MAJOR_NUM, DRIVER_NAME, &dpram_recovery_fops); + if (ret < 0) { + goto err; + } + + dpram_rec_class = class_create(THIS_MODULE, "rec"); + if (IS_ERR(dpram_rec_class)) { + ret = -EFAULT; + goto err1; + } + + dpram_rec_dev_t = device_create(dpram_rec_class, NULL, MKDEV(MAJOR_NUM, 0), NULL, DRIVER_NAME); + if (IS_ERR(dpram_rec_dev_t)) { + ret = -EFAULT; + goto err2; + } + + return 0; + +err2: + class_destroy(dpram_rec_class); + +err1: + unregister_chrdev(MAJOR_NUM, DRIVER_NAME); + +err: + return ret; +} + +/* Dpram Interrupt register */ +static irqreturn_t phone_active_irq_handler(int irq, void *dev_id) +{ + + printk(KERN_ERR "Received interrupt for PHONE ACTIVE \n"); + if (gpio_get_value(GPIO_QSC_PHONE_ACTIVE)) { + printk(KERN_ALERT "%s: Phone Active high and Modem is ON\n", __func__); + } else { + printk(KERN_ALERT "%s: Phone Active Low and Modem is OFF\n", __func__); + } + return IRQ_HANDLED; +} + +static int register_interrupt_handler(void) +{ + int retval = 0, phone_active_irq; + phone_active_irq = gpio_to_irq(IRQ_QSC_PHONE_ACTIVE); + + /* phone active interrupt */ + retval = request_irq(phone_active_irq, phone_active_irq_handler, IRQF_DISABLED, "QSC_ACTIVE", NULL); + if (retval) { + printk(KERN_ERR "Phone active interrupt handler failed.\n"); + } + + return 0; +} + +/* + * DPRAM DRIVER INITIALIZE FUNCTIONs + */ +int dpram_init_hw(void) +{ + int rv; + int phone_active_irq, dpram_wakeup_irq; + + /* 1) Initialize the interrupt pins */ + irq_set_irq_type(IRQ_DPRAM_AP_INT_N, IRQ_TYPE_LEVEL_LOW); + rv = gpio_request(IRQ_QSC_INT, "gpx1_0"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_0\n", __func__); + goto err; + } + dpram_wakeup_irq = gpio_to_irq(IRQ_QSC_INT); + s3c_gpio_cfgpin(GPIO_C210_DPRAM_INT_N, S3C_GPIO_SFN(0xFF)); + s3c_gpio_setpull(GPIO_C210_DPRAM_INT_N, S3C_GPIO_PULL_NONE); + irq_set_irq_type(dpram_wakeup_irq, IRQ_TYPE_EDGE_RISING); + + rv = gpio_request(IRQ_QSC_PHONE_ACTIVE, "gpx1_6"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_6\n", __func__); + goto err1; + } + + phone_active_irq = gpio_to_irq(IRQ_QSC_PHONE_ACTIVE); + + s3c_gpio_setpull(GPIO_QSC_PHONE_ACTIVE, S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(GPIO_QSC_PHONE_RST, S3C_GPIO_PULL_NONE); + irq_set_irq_type(phone_active_irq, IRQ_TYPE_EDGE_FALLING); + /* 4)gpio e3-e4 are for Modem if */ + + s3c_gpio_cfgpin(S5PV310_GPE3_0_MDM_DATA_0, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_1_MDM_DATA_1, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_2_MDM_DATA_2, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_3_MDM_DATA_3, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_4_MDM_DATA_4, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_5_MDM_DATA_5, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_6_MDM_DATA_6, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE3_7_MDM_DATA_7, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + s3c_gpio_cfgpin(S5PV310_GPE4_0_MDM_DATA_8, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_1_MDM_DATA_9, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_2_MDM_DATA_10, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_3_MDM_DATA_11, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_4_MDM_DATA_12, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_5_MDM_DATA_13, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_6_MDM_DATA_14, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE4_7_MDM_DATA_15, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + s3c_gpio_cfgpin(S5PV310_GPE0_0_MDM_WEn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_1_MDM_CSn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_2_MDM_Rn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_3_MDM_IRQn, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + s3c_gpio_cfgpin(S5PV310_GPE0_4_MDM_ADVN, S3C_GPIO_SFN(S5PV310_MDM_IF_SEL)); + + rv = gpio_request(GPIO_PDA_ACTIVE, "GPY4_2"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPY4_2\n", __func__); + goto err2; + } + + rv = gpio_request(GPIO_QSC_PHONE_ON, "GPC1_1"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPC1_1\n", __func__); + goto err3; + } + + rv = gpio_request(GPIO_QSC_PHONE_RST, "GPX1_4"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPX1_4\n", __func__); + goto err4; + } + + s5p_gpio_set_drvstr(GPIO_QSC_PHONE_RST, S5P_GPIO_DRVSTR_LV4); /*To increase driving strength of this pin */ + + /*To config Not Connected pin GPY4_6 to I/P with no pullup */ + rv = gpio_request(GPIO_CP_REQ_RESET, "GPY4_6"); + if (rv < 0) { + printk("IDPRAM: [%s] failed to get gpio GPY4_6\n", __func__); + goto err5; + } + + gpio_direction_input(GPIO_CP_REQ_RESET); + s3c_gpio_setpull(GPIO_CP_REQ_RESET, S3C_GPIO_PULL_NONE); + + /* 5)PDA_ACTIVE, QSC_PHONE_ON, QSC_RESET_N */ + gpio_direction_output(GPIO_PDA_ACTIVE, GPIO_LEVEL_HIGH); + gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_HIGH); + s3c_gpio_setpull(GPIO_QSC_PHONE_ON, S3C_GPIO_PULL_NONE); + gpio_direction_output(GPIO_QSC_PHONE_RST, GPIO_LEVEL_LOW); + + return 0; + +err5: gpio_free(GPIO_QSC_PHONE_RST); +err4: gpio_free(GPIO_QSC_PHONE_ON); +err3: gpio_free(GPIO_PDA_ACTIVE); +err2: gpio_free(IRQ_QSC_PHONE_ACTIVE); +err1: gpio_free(IRQ_QSC_INT); +err: return rv; +} + +static int __devinit dpram_recovery_probe(struct platform_device *pdev) +{ + int err = 0; + g_TotFrame = 0; + + printk(KERN_ERR "[DPRAM_RECOVERY] %s() ...\n", __func__); + + dpram = kmalloc(sizeof(struct dpram_dev), GFP_KERNEL); + if (dpram == NULL) { + printk(KERN_ERR "dpram recovery device allocation failed!!\n"); + err = -ENOMEM; + goto out; + } + + if (dpram_recovery_ioremap(dpram) < 0) { + printk(KERN_ERR "Dpram recovery ioremap failed!\n"); + err = -EFAULT; + goto out_err1; + } + + err = register_dpram_rec_device(); + if (err) { + printk(KERN_ERR "Failed to register dpram recovery device.\n"); + goto out_err2; + } + + err = dpram_init_hw(); + if (err < 0) { + printk("dpram_init_hw() failed\n"); + goto out_err2; + } + + err = register_interrupt_handler(); + if (err < 0) { + printk("register_interrupt_handler() failed!!!\n"); + goto out_err3; + } + + printk(KERN_ERR "%s %d\n", __func__, __LINE__); + + return 0; + +out_err3: + gpio_free(IRQ_QSC_PHONE_ACTIVE); + +out_err2: + iounmap(dpram); + +out_err1: + kfree(dpram); + +out: + return err; +} + + +static int dpram_recovery_suspend(struct device *pdev) +{ + return 0; +} + +static int dpram_recovery_resume(struct device *pdev) +{ + return 0; +} + +static const struct dev_pm_ops dpram_recovery_pm_ops = { + .suspend = dpram_recovery_suspend, + .resume = dpram_recovery_resume, +}; + +static struct platform_driver dpram_recovery_driver = { + .probe = dpram_recovery_probe, + .driver = { + .name = "dpram-recovery", + .pm = &dpram_recovery_pm_ops, + }, +}; + +static int __init dpram_recovery_init(void) +{ + return platform_driver_register(&dpram_recovery_driver); +} + +module_init(dpram_recovery_init); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DPRAM Device Driver for recovery"); diff --git a/drivers/dpram/raffaello/dpram_recovery.h b/drivers/dpram/raffaello/dpram_recovery.h new file mode 100644 index 0000000..38a76ae --- /dev/null +++ b/drivers/dpram/raffaello/dpram_recovery.h @@ -0,0 +1,132 @@ +#ifndef __DPRAM_RECOVERY_H__ +#define __DPRAM_RECOVERY_H__ + + + +/* interupt masks */ +#define MASK_CMD_FOTA_IMG_RECEIVE_READY_RESP 0x0100 +#define MASK_CMD_FOTA_IMG_SEND_RESP 0x0200 +#define MASK_CMD_FOTA_SEND_DONE_RESP 0x0300 +#define MASK_CMD_FOTA_UPDATE_START_RESP 0x0400 +#define MASK_CMD_FOTA_UPDATE_STATUS_IND 0x0500 +#define MASK_CMD_FOTA_UPDATE_END_IND 0x0C00 + +/* FORMAT */ +#define CMD_FOTA_IMG_RECEIVE_READY_REQ 0x9100 +#define CMD_FOTA_IMG_SEND_REQ 0x9200 +#define CMD_FOTA_SEND_DONE_REQ 0x9300 +#define CMD_FOTA_UPDATE_START_REQ 0x9400 +#define CMD_FOTA_UPDATE_STATUS_IND 0x9500 +#define CMD_FOTA_INIT_START_REQ 0x9A00 +#define CMD_FOTA_INIT_START_RES 0x9B00 +#define CMD_FOTA_UPDATE_END_IND 0x9C00 + +#define CMD_RETRY 0 +#define CMD_TRUE 1 +#define CMD_FALSE -1 + +#define CMD_DL_SEND_DONE_REQ 0x9600 +#define CMD_PHONE_BOOT_UPDATE 0x0001 +#define MASK_CMD_SEND_DONE_RESPONSE 0x0700 +#define MASK_CMD_STATUS_UPDATE_NOTIFICATION 0x0800 +#define MASK_CMD_UPDATE_DONE_NOTIFICATION 0x0900 +#define MASK_CMD_IMAGE_SEND_RESPONSE 0x0500 + +/* Result mask */ +#define MASK_CMD_RESULT_FAIL 0x0002 +#define MASK_CMD_RESULT_SUCCESS 0x0001 + +#define MASK_CMD_VALID 0x8000 +#define MASK_PDA_CMD 0x1000 +#define MASK_PHONE_CMD 0x2000 + +#define MAGIC_FODN 0x4E444F46 /* PDA initiate phone code */ +#define MAGIC_FOTA 0x41544C44 /* PDA initiate phone code */ +#define MAGIC_DMDL 0x444D444C +#define MAGIC_ALARMBOOT 0x00410042 + +/* DPRAM */ +#define DPRAM_BASE_ADDR S5P_PA_MODEMIF +#define DPRAM_MAGIC_CODE_SIZE 0x4 +#define DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS (DPRAM_MAGIC_CODE_SIZE) +#define DPRAM_PHONE2PDA_INTERRUPT_ADDRESS (0x3FFE) +#define DPRAM_PDA2PHONE_INTERRUPT_ADDRESS (0x3FFC) +#define DPRAM_BUFFER_SIZE (DPRAM_PDA2PHONE_INTERRUPT_ADDRESS - DPRAM_PDA2PHONE_FORMATTED_START_ADDRESS) +#define BSP_DPRAM_BASE_SIZE 0x4000 /* 16KB DPRAM in Mirage */ +#define DPRAM_END_OF_ADDRESS (BSP_DPRAM_BASE_SIZE - 1) +#define DPRAM_INTERRUPT_SIZE 0x2 +#define DPRAM_INDEX_SIZE 0x2 +#define DELTA_PACKET_SIZE (0x4000 - 0x4 - 0x4) +#define WRITEIMG_HEADER_SIZE 8 +#define WRITEIMG_TAIL_SIZE 4 +#define WRITEIMG_BODY_SIZE (DPRAM_BUFFER_SIZE - WRITEIMG_HEADER_SIZE - WRITEIMG_TAIL_SIZE) +#define FODN_DEFAULT_WRITE_LEN WRITEIMG_BODY_SIZE +#define DPRAM_START_ADDRESS 0 +#define DPRAM_END_OF_ADDRESS (BSP_DPRAM_BASE_SIZE - 1) +#define DPRAM_SIZE BSP_DPRAM_BASE_SIZE + +/* ioctl commands */ +#define IOCTL_ST_FW_UPDATE _IO('D', 0x1) +#define IOCTL_CHK_STAT _IO('D', 0x2) +#define IOCTL_MOD_PWROFF _IO('D', 0x3) +#define IOCTL_WRITE_MAGIC_CODE _IO('D', 0x4) +#define IOCTL_ST_FW_DOWNLOAD _IO('D', 0x5) + +#define GPIO_QSC_INT GPIO_C210_DPRAM_INT_N +#define IRQ_QSC_INT GPIO_QSC_INT + +/* Common */ +#define TRUE 1 +#define FALSE 0 + +#define GPIO_IN 0 +#define GPIO_OUT 1 +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +#define START_INDEX 0x007F +#define END_INDEX 0x007E + +#define DPRAM_MODEM_MSG_SIZE 0x100 + +typedef struct { + unsigned int int2ap; + unsigned int int2msm; + unsigned int mifcon; + unsigned int mifpcon; + unsigned int msmintclr; + unsigned int dma_tx_adr; + unsigned int dma_rx_adr; +} IDPRAM_SFR; + +/* It is recommended that S5PC110 write data with half-word access on the interrupt port because +S5PC100 overwrites tha data in INT2AP if there are INT2AP and INT2MSM sharing the same word */ +#define IDPRAM_INT2MSM_MASK 0xFF + +#define IDPRAM_MIFCON_INT2APEN (1<<2) +#define IDPRAM_MIFCON_INT2MSMEN (1<<3) +#define IDPRAM_MIFCON_DMATXREQEN_0 (1<<16) +#define IDPRAM_MIFCON_DMATXREQEN_1 (1<<17) +#define IDPRAM_MIFCON_DMARXREQEN_0 (1<<18) +#define IDPRAM_MIFCON_DMARXREQEN_1 (1<<19) +#define IDPRAM_MIFCON_FIXBIT (1<<20) + +#define IDPRAM_MIFPCON_ADM_MODE (1<<6) /* mux / demux mode */ + +/* end */ + +struct dpram_firmware { + char *firmware; + int size; + int image_type; +}; + +struct stat_info { + int pct; + char msg[DPRAM_MODEM_MSG_SIZE]; +}; + +#define DPRAM_MODEM_DELTA_IMAGE 0 +#define DPRAM_MODEM_FULL_IMAGE 1 + +#endif /* __DPRAM_RECOVERY_H__ */ |