/*++ Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved. This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd. and may contains trade secrets and/or other confidential information of ChipOne Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party, in whole or in part, without prior written consent of ChipOne. THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR IMPLIED WARRANTIES. File Name: flash.c Abstract: flash operation, read write etc. Author: Zhimin Tian Date : 10 30,2012 Version: 0.1[.revision] History : Change logs. --*/ #include "icn83xx.h" struct file *fp; int g_status = R_OK; static char fw_mode = 0; static int fw_size = 0; static unsigned char *fw_buf; void icn83xx_rawdatadump(short *mem, int size, char br) { int i; for(i=0;i<size; i++) { if((i!=0)&&(i%br == 0)) printk("\n"); printk(" %5d", mem[i]); } printk("\n"); } void icn83xx_memdump(char *mem, int size) { int i; for(i=0;i<size; i++) { if(i%16 == 0) printk("\n"); printk(" 0x%2x", mem[i]); } printk("\n"); } int icn83xx_checksum(int sum, char *buf, unsigned int size) { int i; for(i=0; i<size; i++) { sum = sum + buf[i]; } return sum; } int icn83xx_update_status(int status) { // flash_info("icn83xx_update_status: %d\n", status); g_status = status; return 0; } int icn83xx_get_status(void) { return g_status; } void icn83xx_set_fw(int size, unsigned char *buf) { fw_size = size; fw_buf = buf; } /*********************************************************************************************** Name : icn83xx_writeInfo Input : addr, value Output : function : write Flash Info ***********************************************************************************************/ int icn83xx_writeInfo(unsigned short addr, char value) { int ret = -1; char temp_buf[3]; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); temp_buf[0] = value; ret = icn83xx_i2c_txdata(232, temp_buf, 1); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(5); return 0; } /*********************************************************************************************** Name : icn83xx_readInfo Input : Output : function : read Flash info ***********************************************************************************************/ int icn83xx_readInfo(unsigned short addr, char *value) { int ret = -1; char temp_buf[3]; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); ret = icn83xx_i2c_rxdata(232, value, 1); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); return 0; } /*********************************************************************************************** Name : icn83xx_writeReg Input : addr, value Output : function : write MCU xdata and reg ***********************************************************************************************/ int icn83xx_writeReg(unsigned short addr, char value) { int ret = -1; char temp_buf[3]; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(224, temp_buf, 2); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); temp_buf[0] = value; ret = icn83xx_i2c_txdata(226, temp_buf, 1); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(5); return 0; } /*********************************************************************************************** Name : icn83xx_readReg Input : Output : function : read MCU xdata and reg ***********************************************************************************************/ int icn83xx_readReg(unsigned short addr, char *value) { int ret = -1; char temp_buf[3]; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(224, temp_buf, 2); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); ret = icn83xx_i2c_rxdata(226, value, 1); if (ret < 0) { op_error("%s failed! ret: %d\n", __func__, ret); return -1; } mdelay(2); return 0; } /*********************************************************************************************** Name : icn83xx_open_fw Input : *fw Output : file size function : open the fw file, and return total size ***********************************************************************************************/ int icn83xx_open_fw( char *fw) { int file_size; mm_segment_t fs; struct inode *inode = NULL; if(strcmp(fw, "icn83xx_firmware") == 0) { fw_mode = 1; //use inner array return fw_size; } else { fw_mode = 0; //use file in file system } fp = filp_open(fw, O_RDONLY, 0); if (IS_ERR(fp)) { flash_error("read fw file error\n"); return -1; } else flash_info("open fw file ok\n"); inode = fp->f_dentry->d_inode; file_size = inode->i_size; flash_info("file size: %d\n", file_size); fs = get_fs(); set_fs(KERNEL_DS); return file_size; } /*********************************************************************************************** Name : icn83xx_read_fw Input : offset length, read length buf, return buffer Output : function : read data to buffer ***********************************************************************************************/ int icn83xx_read_fw(int offset, int length, char *buf) { loff_t pos = offset; if(fw_mode == 1) { memcpy(buf, fw_buf+offset, length); } else { vfs_read(fp, buf, length, &pos); } // icn83xx_memdump(buf, length); return 0; } /*********************************************************************************************** Name : icn83xx_close_fw Input : Output : function : close file ***********************************************************************************************/ int icn83xx_close_fw(void) { if(fw_mode == 0) { filp_close(fp, NULL); } return 0; } /*********************************************************************************************** Name : icn83xx_readVersion Input : void Output : function : return version ***********************************************************************************************/ int icn83xx_readVersion(void) { int err = 0; char tmp[2]; short CurVersion; err = icn83xx_i2c_rxdata(12, tmp, 2); if (err < 0) { calib_error("%s failed: %d\n", __func__, err); return err; } CurVersion = (tmp[0]<<8) | tmp[1]; return CurVersion; } /*********************************************************************************************** Name : icn83xx_changemode Input : normal/factory/config Output : function : change work mode ***********************************************************************************************/ int icn83xx_changemode(char mode) { char value = 0x0; icn83xx_write_reg(0, mode); mdelay(1); icn83xx_read_reg(1, &value); while(value != 0) { mdelay(1); icn83xx_read_reg(1, &value); } // calib_info("icn83xx_changemode ok\n"); return 0; } /*********************************************************************************************** Name : icn83xx_readrawdata Input : rownum and length Output : function : read one row rawdata ***********************************************************************************************/ int icn83xx_readrawdata(char *buffer, char row, char length) { int err = 0; int i; // calib_info("readrawdata: %d, length: %d\n", row, length); icn83xx_write_reg(3, row); mdelay(1); err = icn83xx_i2c_rxdata(160, buffer, length); if (err < 0) { calib_error("%s failed: %d\n", __func__, err); return err; } for(i=0; i<length; i=i+2) { swap_ab(buffer[i], buffer[i+1]); } return err; } /*********************************************************************************************** Name : icn83xx_scanTP Input : Output : function : scan one frame rawdata ***********************************************************************************************/ int icn83xx_scanTP(void) { char value = 0; icn83xx_write_reg(2, 0x0); mdelay(1); icn83xx_read_reg(2, &value); while(value != 1) { mdelay(1); icn83xx_read_reg(2, &value); } // calib_info("icn83xx_scanTP ok\n"); return 0; } /*********************************************************************************************** Name : icn83xx_readTP Input : rownum and columnnum Output : function : read one frame rawdata ***********************************************************************************************/ int icn83xx_readTP(char row_num, char column_num, char *buffer) { int err = 0; int i; // calib_info("icn83xx_readTP\n"); icn83xx_changemode(1); icn83xx_scanTP(); for(i=0; i<row_num; i++) { icn83xx_readrawdata(&buffer[i*16*2], i, column_num*2); } icn83xx_changemode(0); return err; } /*********************************************************************************************** Name : icn83xx_goto_progmode Input : Output : function : change MCU to progmod ***********************************************************************************************/ int icn83xx_goto_progmode(void) { int ret = -1; // char value[64]; char regValue = 0; flash_info("icn83xx_goto_progmode\n"); ret = icn83xx_readReg(0x009, ®Value); if(ret != 0) return ret; flash_info("[0x009]: 0x%x\n", regValue); // open clock if(regValue != 0xDF) { icn83xx_changemode(2); ret = icn83xx_writeReg(0x002, 0x00); if(ret != 0) return ret; ret = icn83xx_writeReg(0x009, 0xDF); if(ret != 0) return ret; ret = icn83xx_writeReg(0x010, 0x00); if(ret != 0) return ret; } /* addr = 0x0; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } temp_buf[0] = 0xff; ret = icn83xx_i2c_txdata(232, temp_buf, 1); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } */ ret = icn83xx_writeInfo(0x0, 0xff); if(ret != 0) return ret; /* addr = 0x1; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } temp_buf[0] = 0xff; ret = icn83xx_i2c_txdata(232, temp_buf, 1); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } */ ret = icn83xx_writeInfo(0x1, 0xff); if(ret != 0) return ret; ret = icn83xx_writeInfo(0x10, 0xff); if(ret != 0) return ret; ret = icn83xx_writeInfo(0x11, 0xff); if(ret != 0) return ret; /* addr = 0xf00; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(224, temp_buf, 2); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } temp_buf[0] = 0x1; ret = icn83xx_i2c_txdata(226, temp_buf, 1); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } */ ret = icn83xx_writeReg(0xf00, 1); if(ret != 0) return ret; icn83xx_ts_reset(); //mdelay(100); msleep(100); return 0; } /*********************************************************************************************** Name : icn83xx_check_progmod Input : Output : function : check if MCU at progmode or not ***********************************************************************************************/ int icn83xx_check_progmod(void) { int ret; unsigned char ucTemp = 0x0; ret = icn83xx_prog_i2c_rxdata(0x0, &ucTemp, 1); flash_info("icn83xx_check_progmod: 0x%x\n", ucTemp); if(ret < 0) { flash_error("icn83xx_check_progmod error, ret: %d\n", ret); return ret; } return 0; } /*********************************************************************************************** Name : icn83xx_uu Input : Output : function : unlock flash ***********************************************************************************************/ int icn83xx_uu(void) { unsigned char ucTemp = 0x0; ucTemp = 0x1e; icn83xx_prog_i2c_txdata(0x050a, &ucTemp, 1); ucTemp = 0x10; icn83xx_prog_i2c_txdata(0x050b, &ucTemp, 1); return 0; } /*********************************************************************************************** Name : icn83xx_ll Input : Output : function : lock flash ***********************************************************************************************/ void icn83xx_ll(void) { unsigned char ucTemp = 0x0; ucTemp = 0xcc; icn83xx_prog_i2c_txdata(0x050a, &ucTemp, 1); ucTemp = 0xcc; icn83xx_prog_i2c_txdata(0x050b, &ucTemp, 1); } /*********************************************************************************************** Name : icn83xx_op1 Input : Output : function : erase flash ***********************************************************************************************/ int icn83xx_op1(char info, unsigned short offset, unsigned int size) { int count = 0; unsigned char ucTemp = 0x0; unsigned short uiAddress = 0x0; int i; icn83xx_uu(); for(i=0; i<size; ) { uiAddress = offset + i; // flash_info("uiAddress: 0x%x\n", uiAddress); ucTemp = U16LOBYTE(uiAddress); icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1); ucTemp = U16HIBYTE(uiAddress); icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1); ucTemp = 0x02; icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); ucTemp = 0x01; count = 0; while(ucTemp) { icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1); count++; if(count > 5000) { flash_error("op1 ucTemp: 0x%x\n", ucTemp); return 1; } } i = i+1024; } icn83xx_ll(); return 0; } /*********************************************************************************************** Name : icn83xx_op2 Input : Output : function : progm flash ***********************************************************************************************/ int icn83xx_op2(char info, unsigned short offset, unsigned char * buffer, unsigned int size) { int count = 0; unsigned int flash_size; unsigned char ucTemp; unsigned short uiAddress; ucTemp = 0x00; uiAddress = 0x1000; icn83xx_prog_i2c_txdata(uiAddress, buffer, size); icn83xx_uu(); ucTemp = U16LOBYTE(offset); icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1); ucTemp = U16HIBYTE(offset); icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1); icn83xx_prog_i2c_txdata(0x0504, (char *)&uiAddress, 2); //ensure size is even if(size%2 != 0) { flash_info("write op size: %d\n", size); flash_size = size+1; } else flash_size = size; ucTemp = U16LOBYTE(flash_size); icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1); ucTemp = U16HIBYTE(flash_size); icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1); ucTemp = 0x01; if(info > 0) ucTemp = 0x01 | (1<<3); icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); // while(ucTemp) { icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1); count++; if(count > 5000) { flash_error("op2 ucTemp: 0x%x\n", ucTemp); return 1; } } icn83xx_ll(); return 0; } /*********************************************************************************************** Name : icn83xx_op3 Input : Output : function : read flash ***********************************************************************************************/ int icn83xx_op3(char info, unsigned short offset, unsigned char * buffer, unsigned int size) { int count = 0; unsigned int flash_size; unsigned char ucTemp; unsigned short uiAddress; ucTemp = 0x00; uiAddress = 0x1000; icn83xx_uu(); ucTemp = U16LOBYTE(offset); icn83xx_prog_i2c_txdata(0x0502, &ucTemp, 1); ucTemp = U16HIBYTE(offset); icn83xx_prog_i2c_txdata(0x0503, &ucTemp, 1); icn83xx_prog_i2c_txdata(0x0504, (unsigned char*)&uiAddress, 2); //ensure size is even if(size%2 != 0) { flash_info("read op size: %d\n", size); flash_size = size+1; } else flash_size = size; ucTemp = U16LOBYTE(flash_size); icn83xx_prog_i2c_txdata(0x0506, &ucTemp, 1); ucTemp = U16HIBYTE(flash_size); icn83xx_prog_i2c_txdata(0x0507, &ucTemp, 1); ucTemp = 0x40; if(info > 0) ucTemp = 0x40 | (1<<3); icn83xx_prog_i2c_txdata(0x0500, &ucTemp, 1); ucTemp = 0x01; while(ucTemp) { icn83xx_prog_i2c_rxdata(0x0501, &ucTemp, 1); count++; if(count > 5000) { flash_error("op3 ucTemp: 0x%x\n", ucTemp); return 1; } } icn83xx_ll(); icn83xx_prog_i2c_rxdata(uiAddress, buffer, size); return 0; } /*********************************************************************************************** Name : icn83xx_goto_nomalmode Input : Output : function : when prog flash ok, change flash info flag ***********************************************************************************************/ int icn83xx_goto_nomalmode(void) { int ret = -1; //unsigned short addr = 0; char temp_buf[3]; flash_info("icn83xx_goto_nomalmode\n"); temp_buf[0] = 0x03; icn83xx_prog_i2c_txdata(0x0f00, temp_buf, 1); msleep(100); /* addr = 0; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); temp_buf[2] = 0; ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } icn83xx_i2c_rxdata(232, &temp_buf[2], 1); flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]); */ ret = icn83xx_readInfo(0, &temp_buf[2]); if(ret != 0) return ret; flash_info("temp_buf[2]: 0x%x\n", temp_buf[2]); if(temp_buf[2] == 0xff) { /* addr = 0; temp_buf[0] = U16HIBYTE(addr); temp_buf[1] = U16LOBYTE(addr); ret = icn83xx_i2c_txdata(230, temp_buf, 2); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } temp_buf[0] = 0x11; ret = icn83xx_i2c_txdata(232, temp_buf, 1); if (ret < 0) { pr_err("write reg failed! ret: %d\n", ret); return -1; } */ ret = icn83xx_writeInfo(0, 0x11); if(ret != 0) return ret; } return 0; } /*********************************************************************************************** Name : icn83xx_read_fw_Ver Input : fw Output : function : read fw version ***********************************************************************************************/ short icn83xx_read_fw_Ver(char *fw) { short FWversion; char tmp[2]; int file_size; file_size = icn83xx_open_fw(fw); if(file_size < 0) { return -1; } icn83xx_read_fw(0x4000, 2, &tmp[0]); icn83xx_close_fw(); FWversion = (tmp[0]<<8)|tmp[1]; // flash_info("FWversion: 0x%x\n", FWversion); return FWversion; } /*********************************************************************************************** Name : icn83xx_fw_update Input : fw Output : function : upgrade fw ***********************************************************************************************/ E_UPGRADE_ERR_TYPE icn83xx_fw_update(char *fw) { int file_size, last_length; int j, num; int checksum_bak = 0; int checksum = 0; char temp_buf[B_SIZE]; #ifdef ENABLE_BYTE_CHECK char temp_buf1[B_SIZE]; #endif file_size = icn83xx_open_fw(fw); if(file_size < 0) { icn83xx_update_status(R_FILE_ERR); return R_FILE_ERR; } if(icn83xx_goto_progmode() != 0) { if(icn83xx_check_progmod() < 0) { icn83xx_update_status(R_STATE_ERR); icn83xx_close_fw(); return R_STATE_ERR; } } // msleep(50); if(icn83xx_op1(0, 0, file_size) != 0) { flash_error("icn83xx_op1 error\n"); icn83xx_update_status(R_ERASE_ERR); icn83xx_close_fw(); return R_ERASE_ERR; } icn83xx_update_status(5); num = file_size/B_SIZE; for(j=0; j < num; j++) { icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf); // icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE); // icn83xx_memdump(temp_buf1, B_SIZE); if(icn83xx_op2(0, j*B_SIZE, temp_buf, B_SIZE) != 0) { icn83xx_update_status(R_PROGRAM_ERR); icn83xx_close_fw(); return R_PROGRAM_ERR; } checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, B_SIZE); icn83xx_update_status(5+(int)(60*j/num)); } last_length = file_size - B_SIZE*j; if(last_length > 0) { icn83xx_read_fw(j*B_SIZE, last_length, temp_buf); // icn83xx_op3(0, j*B_SIZE, temp_buf1, B_SIZE); // icn83xx_memdump(temp_buf1, B_SIZE); if(icn83xx_op2(0, j*B_SIZE, temp_buf, last_length) != 0) { icn83xx_update_status(R_PROGRAM_ERR); icn83xx_close_fw(); return R_PROGRAM_ERR; } checksum_bak = icn83xx_checksum(checksum_bak, temp_buf, last_length); } icn83xx_close_fw(); icn83xx_update_status(65); #ifdef ENABLE_BYTE_CHECK file_size = icn83xx_open_fw(fw); num = file_size/B_SIZE; #endif for(j=0; j < num; j++) { #ifdef ENABLE_BYTE_CHECK icn83xx_read_fw(j*B_SIZE, B_SIZE, temp_buf1); #endif icn83xx_op3(0, j*B_SIZE, temp_buf, B_SIZE); checksum = icn83xx_checksum(checksum, temp_buf, B_SIZE); #ifdef ENABLE_BYTE_CHECK if(memcmp(temp_buf1, temp_buf, B_SIZE) != 0) { flash_error("cmp error, %d\n", j); icn83xx_memdump(temp_buf1, B_SIZE); icn83xx_memdump(temp_buf, B_SIZE); icn83xx_update_status(R_VERIFY_ERR); #ifdef ENABLE_BYTE_CHECK icn83xx_close_fw(); #endif return R_VERIFY_ERR; //while(1); } #endif icn83xx_update_status(65+(int)(30*j/num)); } #ifdef ENABLE_BYTE_CHECK last_length = file_size - B_SIZE*j; #endif if(last_length > 0) { #ifdef ENABLE_BYTE_CHECK icn83xx_read_fw(j*B_SIZE, last_length, temp_buf1); #endif icn83xx_op3(0, j*B_SIZE, temp_buf, last_length); checksum = icn83xx_checksum(checksum, temp_buf, last_length); #ifdef ENABLE_BYTE_CHECK if(memcmp(temp_buf1, temp_buf, last_length) != 0) { flash_error("cmp error, %d\n", j); icn83xx_memdump(temp_buf1, last_length); icn83xx_memdump(temp_buf, last_length); icn83xx_update_status(R_VERIFY_ERR); #ifdef ENABLE_BYTE_CHECK icn83xx_close_fw(); #endif return R_VERIFY_ERR; //while(1); } #endif } #ifdef ENABLE_BYTE_CHECK icn83xx_close_fw(); #endif flash_info("checksum_bak: 0x%x, checksum: 0x%x\n", checksum_bak, checksum); if(checksum_bak != checksum) { flash_error("upgrade checksum error\n"); icn83xx_update_status(R_VERIFY_ERR); return R_VERIFY_ERR; } if(icn83xx_goto_nomalmode() != 0) { flash_error("icn83xx_goto_nomalmode error\n"); icn83xx_update_status(R_STATE_ERR); return R_STATE_ERR; } icn83xx_update_status(R_OK); flash_info("upgrade ok\n"); return R_OK; }