/*++ 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;if_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 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; }