Linux的芯片驱动firmware自动升级之二:MELFAS的TP升级实例
时间:10-02
整理:3721RD
点击:
以MELFAS的MS6000芯片固件升级实例,说明一般的数组格式的IMAGE文件烧录的过程。该芯片需要PIN脚组合完成一定的时序并实现一组命令码进入烧录模式,并且在烧录模式下的I2C地址是0XFA(跟芯片正常工作时的地址0X40不同),在烧录完毕后进行复位并开始相应正常的TP操作。芯片大致的烧录了流程图如下:
实现代码如下:
(1)基础宏定义
[cpp] view plaincopy- #define FIAMWARE_NAME "MELFAS_W105.h" //数组格式IMAGE的名字
- static unsigned char MS6000CTPM_FW[] = //以数组划分空间存储烧录映象
- {
- #include FIAMWARE_NAME
- };
- #define MS6000_ADDR_MODULE_REVISION 0x98
- #define MS6000_ADDR_FIRMWARE_VERSION 0x9C //烧录IMAGE中对应的特定字节地址
- #define MS6000_TRANSFER_LENGTH 64 //一次烧录的packet字节数
- /*ISP command*/
- #define MS6000_ISP_CMD_ERASE 0x02
- #define MS6000_ISP_CMD_ERASE_TIMING 0x0F
- #define MS6000_ISP_CMD_PROGRAM_FLASH 0x03
- #define MS6000_ISP_CMD_READ_FLASH 0x04
- #define MS6000_ISP_CMD_PROGRAM_TIMING 0x0F
- #define MS6000_ISP_CMD_READ_INFORMATION 0x06
- #define MS6000_ISP_CMD_RESET 0x07
- #define MS6000_7BIT_DOWNLOAD_ADDR 0x7D
- #define MS6000_8BIT_DOWNLOAD_ADDR (MS6000_7BIT_DOWNLOAD_ADDR<<1) //linux的i2CCLIent需8位地址
- #define MS6000_I2C_SLAVE_READY_STATUS 0x55
- // MCS6000's responses
- #define MS6000_ISP_ACK_ERASE_DONE 0x82
- #define MS6000_ISP_ACK_PREPARE_ERASE_DONE 0x8F
- #define MS6000_I2C_ACK_PREPARE_PROGRAM 0x8F
- #define MS6000_MDS_ACK_PROGRAM_FLASH 0x83
- #define MS6000_MDS_ACK_READ_FLASH 0x84
- #define MS6000_MDS_ACK_PROGRAM_INFORMATION 0x88
- #define MS6000_MDS_ACK_PROGRAM_LOCKED 0xFE
- #define MS6000_MDS_ACK_READ_LOCKED 0xFE
- #define MS6000_MDS_ACK_FAIL 0xFE
- #define MS6000_ISP_ERASE_TIMING_VALUE_0 0x01
- #define MS6000_ISP_ERASE_TIMING_VALUE_1 0xD4
- #define MS6000_ISP_ERASE_TIMING_VALUE_2 0xC0
- #define MS6000_ISP_PROGRAM_TIMING_VALUE_0 0x00
- #define MS6000_ISP_PROGRAM_TIMING_VALUE_1 0x00
- #define MS6000_ISP_PROGRAM_TIMING_VALUE_2 0x78
(2)I2C烧写和读TP FLASH的函数
注意:该芯片在烧录模式下的单字节读操作和写操作都不需要寄存器地址,只send芯片地址就行。里面用到的i2c_client->address已变换地址。
- static bool mfs_i2c_write_single_byte(unsigned char bufVal)
- {
- int ret;
- unsigned char buf;
- buf = bufVal;
- ret = i2c_master_send(i2c_client, &buf, 1);
- if(ret <= 0){
- printk("mfs_i2c_write_single_byte error line = %d, ret = %d\n", __LINE__, ret);
- return false;
- }
- return true;
- }
- static bool mfs_i2c_read_single_byte(unsigned char *buf)
- {
- int ret;
- ret = i2c_master_recv(i2c_client, buf, 1);
- if(ret <= 0){
- printk("mfs_i2c_read_single_byte error line = %d, ret = %d\n", __LINE__, ret);
- return false;
- }
- return true;
- }
- static int mfs_i2c_read_flash(unsigned char *pBuffer,UINT16 nAddr_start,unsigned char cLength)
- { //将nAddr_start开始的cLength个字节读到pBuffer所指的空间中
- int nRet = MS6000_RET_READ_FLASH_FAILED,i;
- BOOL bRet;
- unsigned char cmd[4],ucTemp;
- // Send Read Flash command [ Read code - address high - address low - size ]
- cmd[0] = MS6000_ISP_CMD_READ_FLASH;
- cmd[1] = (UINT8)((nAddr_start >> 8 ) & 0xFF);
- cmd[2] = (UINT8)((nAddr_start ) & 0xFF);
- cmd[3] = cLength;
- for(i=0;i<4;i++){
- bRet = mfs_i2c_write_single_byte(cmd);
- udelay(15);
- if(bRet == FALSE)
- goto MS6000_I2C_READ_FLASH_FINISH;
- }
- // Read 'Result of command'
- bRet = mfs_i2c_read_single_byte(&ucTemp);
- if( !bRet || ucTemp != MS6000_MDS_ACK_READ_FLASH){
- goto MS6000_I2C_READ_FLASH_FINISH;
- }
- // Read Data [ pCmd[3] == Size ]
- for(i=0; i<(int)cmd[3]; i++){
- udelay(100);
- bRet = mfs_i2c_read_single_byte(pBuffer++);
- if( bRet == FALSE && i!=(int)(cmd[3]-1) )
- goto MS6000_I2C_READ_FLASH_FINISH;
- }
- nRet = MS6000_RET_SUCCESS;
- MS6000_I2C_READ_FLASH_FINISH:
- return nRet;
- }
(3)进入download功能
[cpp] view plaincopy- static void ms6000_write_download_mode_signal(void) //通过RESET脚和EINT脚发出一组组合电平
- {
- int i;
- unsigned char enter_code[14] = { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1 };
- for(i=0; i<14; i++){
- if(enter_code){
- mt_set_GPIO_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);
- mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ONE);
- }
- else{
- mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);
- mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO);
- }
- mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ONE);
- udelay(15);
- mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ZERO);
- mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);
- mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO);
- udelay(100);
- }
- mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ONE);
- udelay(100);
- mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ONE);
- mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);
- }
- static int ms6000_enter_download_mode(void)
- {
- bool bRet;
- int nRet = MS6000_RET_ENTER_DOWNLOAD_MODE_FAILED;
- unsigned char cData=0;
- hwpowerDown(MT65XX_POWER_LDO_VGP2, "TP"); //TKEY_VDD_SET_LOW();
- mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_I2C0_SCA_PIN, GPIO_DIR_OUT);
- mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ZERO);
- mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_I2C0_SDA_PIN, GPIO_DIR_OUT);
- mt_set_gpio_out(GPIO_I2C0_SDA_PIN, GPIO_OUT_ZERO); //I2C变GPIO功能
- mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_OUT); //TKEY_INTR_SET_OUTPUT();
- mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO); //TKEY_INTR_SET_LOW();
- mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
- mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); //TKEY_RESETB_SET_OUTPUT();
- mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO); //若干功能脚均需完成电平拉低的作用
- mdelay(90); //Delay for Stable VDD
- hwPowerOn(MT65XX_POWER_LDO_VGP2, VOL_2800, "TP"); //TKEY_VDD_SET_HIGH();
- mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); //TKEY_CE_SET_HIGH();
- mt_set_gpio_out(GPIO_I2C0_SDA_PIN, GPIO_OUT_ONE); //TKEY_I2C_SDA_SET_HIGH();
- mdelay(25);
- ms6000_write_download_mode_signal(); //写命令码
- mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_SCL);
- mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_SDA); //使能I2C的PIN脚恢复I2C功能
- mdelay(2);
- bRet = mfs_i2c_read_single_byte(&cData);
- if( bRet != TRUE || cData != MS6000_I2C_SLAVE_READY_STATUS ){
- goto MS6000_ENTER_DOWNLOAD_MODE_FINISH;
- }
- else
- printk("respond fROM download mode commande is 0x55 \r\n"); //只有芯片状态返回0x55,才说明进入DOWNLOAD模式
- nRet = MS6000_RET_SUCCESS; //Entering MDS ISP mode finished.
- MS6000_ENTER_DOWNLOAD_MODE_FINISH:
- return nRet;
- }
(4)芯片复位和TP FLASH擦除
[cpp] view plaincopy- static void ms6000_reset_command(void) //不管是升级过程失败还是成功,最后都需要复位并使能芯片
- {
- unsigned char buf;
- mdelay(1);
- buf = MS6000_ISP_CMD_RESET;
- if(mfs_i2c_write_single_byte(buf) == true)
- printk("mfs6000_reset_command reset success \r\n");
- mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
- mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);
- mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE);
- mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP); //恢复EINT的pin功能
- mdelay(180);
- }
- static unsigned char ms6000_GetLibVer(void) //取得新固件中的版本号,以便比较
- {
- unsigned int sz;
- sz = sizeof(MS6000CTPM_FW);
- if(sz > 2){
- return (MS6000CTPM_FW[157]-0X30); //版本号字节数据
- }
- else{
- return 0xff;
- }
- }
- static int ms6000_i2c_prepare_erase_flash(void)
- {
- int nRet = MS6000_RET_PREPARE_ERASE_FLASH_FAILED,i;
- BOOL bRet;
- UINT8 i2c_buffer[4] = { MS6000_ISP_CMD_ERASE_TIMING,
- MS6000_ISP_ERASE_TIMING_VALUE_0,
- MS6000_ISP_ERASE_TIMING_VALUE_1,
- MS6000_ISP_ERASE_TIMING_VALUE_2 };
- UINT8 ucTemp;
- // Send Erase Setting code
- for(i=0; i<4; i++){
- bRet = mfs_i2c_write_single_byte(i2c_buffer);
- if( !bRet ){
- goto MS6000_I2C_PREPARE_ERASE_FLASH_FINISH;
- }
- udelay(15);
- }
- // Read Result
- udelay(500);
- bRet = mfs_i2c_read_single_byte(&ucTemp);
- if( bRet && ucTemp == MS6000_ISP_ACK_PREPARE_ERASE_DONE ){
- nRet = MS6000_RET_SUCCESS;
- }
- MS6000_I2C_PREPARE_ERASE_FLASH_FINISH:
- return nRet;
- }
- static int ms6000_i2c_erase_flash(void)
- {
- int nRet = MS6000_RET_ERASE_FLASH_FAILED,i;
- BOOL bRet;
- UINT8 i2c_buffer[1] = { MS6000_ISP_CMD_ERASE};
- UINT8 ucTemp;
- // Send Erase code
- for(i=0; i<1; i++){
- bRet = mfs_i2c_write_single_byte(i2c_buffer);
- if( !bRet )
- goto MS6000_I2C_ERASE_FLASH_FINISH;
- udelay(15);
- }
- // Read Result
- mdelay(45);
- bRet = mfs_i2c_read_single_byte(&ucTemp);
- if( bRet && ucTemp == MS6000_ISP_ACK_ERASE_DONE ){
- nRet = MS6000_RET_SUCCESS;
- }
- MS6000_I2C_ERASE_FLASH_FINISH:
- return nRet;
- }
(5)预编程和编程函数,以及download映象主函数
[cpp] view plaincopy- static int ms6000_i2c_prepare_program(void)
- {
- int nRet = MS6000_RET_PREPARE_PROGRAM_FAILED,i;
- BOOL bRet;
- UINT8 i2c_buffer[4] = { MS6000_ISP_CMD_PROGRAM_TIMING,
- MS6000_ISP_PROGRAM_TIMING_VALUE_0,
- MS6000_ISP_PROGRAM_TIMING_VALUE_1,
- MS6000_ISP_PROGRAM_TIMING_VALUE_2};
- // Write Program timing information
- for(i=0; i<4; i++){
- bRet = mfs_i2c_write_single_byte(i2c_buffer);
- if( bRet == FALSE )
- goto MS6000_I2C_PREPARE_PROGRAM_FINISH;
- udelay(15);
- }
- udelay(500);
- // Read command's result
- bRet = mfs_i2c_read_single_byte(&i2c_buffer[4]);
- if( bRet == FALSE || i2c_buffer[4] != MS6000_I2C_ACK_PREPARE_PROGRAM)
- goto MS6000_I2C_PREPARE_PROGRAM_FINISH;
- mdelay(100);
- nRet = MS6000_RET_SUCCESS;
- MS6000_I2C_PREPARE_PROGRAM_FINISH:
- return nRet;
- }
- static int ms6000_i2c_program_flash( UINT8 *pData, UINT16 nAddr_start, UINT8 cLength ) //FLASH one packet编程主函数
- { //参数是待编程数据,写入地址,待编程数据长度
- int nRet = MS6000_RET_PROGRAM_FLASH_FAILED;
- int i,j;
- BOOL bRet;
- UINT8 cData;
- UINT8 tmp;
- UINT8 cmd[4];
- // Send program code
- cmd[0] = MS6000_ISP_CMD_PROGRAM_FLASH;
- cmd[1] = (UINT8)((nAddr_start >> 8 ) & 0xFF);
- cmd[2] = (UINT8)((nAddr_start ) & 0xFF);
- cmd[3] = cLength;
- for(i=0; i<4; i++){
- bRet = mfs_i2c_write_single_byte(cmd);
- udelay(15);
- if( bRet == FALSE )
- goto MS6000_I2C_PROGRAM_FLASH_FINISH;
- }
- // Check command result
- bRet = mfs_i2c_read_single_byte(&cData);
- if( bRet == FALSE || cData != MS6000_MDS_ACK_PROGRAM_FLASH ){
- goto MS6000_I2C_PROGRAM_FLASH_FINISH;
- }
- // Program Data
- udelay(150);
- for(i=0; i<(int)cmd[3]; i+=2){ //一次写入两个字节,先写高位,再写低位
- bRet = mfs_i2c_write_single_byte(pData[i+1]);
- if( bRet == FALSE )
- goto MS6000_I2C_PROGRAM_FLASH_FINISH;
- udelay(100); // Delay about 150us
- bRet = mfs_i2c_write_single_byte(pData);
- udelay(150); // Delay about 150us
- if( bRet == FALSE )
- goto MS6000_I2C_PROGRAM_FLASH_FINISH;
- }
- nRet = MS6000_RET_SUCCESS;
- MS6000_I2C_PROGRAM_FLASH_FINISH:
- return nRet;
- }
- static int ms6000_download(const UINT8 *pData, const UINT16 nLength ) //download主函数,参数是映象内存首地址及映象长度
- {
- int i,nRet;
- unsigned char cLength,buffer[MS6000_TRANSFER_LENGTH];
- uint16_t nStart_address=0;
- unsigned char *pOriginal_data;
- //enter in download mode
- nRet = ms6000_enter_download_mode();
- if(nRet != MS6000_RET_SUCCESS)
- goto MS6000_DOWNLOAD_FINISH;
- mdelay(1);
- // Erase Flash
- nRet = ms6000_i2c_prepare_erase_flash();
- if(nRet !=MS6000_RET_SUCCESS){
- goto MS6000_DOWNLOAD_FINISH;
- }
- mdelay(1);
- nRet = ms6000_i2c_erase_flash();
- if(nRet !=MS6000_RET_SUCCESS)
- goto MS6000_DOWNLOAD_FINISH;
- mdelay(1);
- // Verify erase
- nRet = mfs_i2c_read_flash( buffer, 0x00, 16 ); // Must be '0xFF' after erase
- if( nRet != MS6000_RET_SUCCESS )
- goto MS6000_DOWNLOAD_FINISH;
- for(i=0; i<16; i++){
- if( buffer != 0xFF ){
- nRet = MS6000_RET_ERASE_VERIFY_FAILED;
- goto MS6000_DOWNLOAD_FINISH;
- }
- }
- mdelay(1);
- // Prepare for Program flash.
- nRet = ms6000_i2c_prepare_program();
- if( nRet != MS6000_RET_SUCCESS )
- goto MS6000_DOWNLOAD_FINISH;
- mdelay(1);
- // Program flash
- #if 1
- pOriginal_data = (UINT8 *)pData; //保留原始首地址
- nStart_address = 0; //烧录起始地址
- cLength = MS6000_TRANSFER_LENGTH; //一次烧录长度,64B
- for( nStart_address = 0; nStart_address < nLength; nStart_address+=cLength ){
- if( ( nLength - nStart_address ) < MS6000_TRANSFER_LENGTH ){
- cLength = (UINT8)(nLength - nStart_address);
- cLength += (cLength%2); // For odd length.最后不足64B的,补上1字节当偶数处理,因为以WORD烧录
- }
- nRet = ms6000_i2c_program_flash( pOriginal_data, nStart_address, cLength );
- if( nRet != MS6000_RET_SUCCESS ){
- goto MS6000_DOWNLOAD_FINISH;
- }
- pOriginal_data += cLength;
- udelay(500);
- printk("#");
- }
- printk("mfs6000 program finished \r\n");
- #endif
- // Verify flash
- #if 1
- pOriginal_data = (UINT8 *) pData; //保留原始首地址
- nStart_address = 0;
- cLength = MS6000_TRANSFER_LENGTH;
- for( nStart_address = 0; nStart_address < nLength; nStart_address+=cLength ){
- if( ( nLength - nStart_address ) < MS6000_TRANSFER_LENGTH ){
- cLength = (UINT8)(nLength - nStart_address);
- cLength += (cLength%2); // For odd length.
- }
- // Read flash
- nRet = mfs_i2c_read_flash( buffer, nStart_address, cLength );
- // Comparing
- for(i=0; i<(int)cLength; i++){
- if( buffer != pOriginal_data ){ //如果读出的对应地址字节与原始对应地址数据不同
- nRet = MS6000_RET_PROGRAM_VERIFY_FAILED;
- goto MS6000_DOWNLOAD_FINISH;
- }
- }
- pOriginal_data += cLength;
- udelay(500);
- printk("*");
- }
- printk("mfs6000 Verify finished \r\n");
- #endif
- nRet = MS6000_RET_SUCCESS;
- MS6000_DOWNLOAD_FINISH:
- ms6000_reset_command();
- return nRet;
- }
(6)升级主函数,以及TP probe函数中的处理
[cpp] view plaincopy- static int ms6000_firmware_upgrade()
- {
- unsigned char NewFwVersion,OldFwVersion;
- uint16_t nBinary_length = 0;
- int nRead = 0;
- unsigned char *ptrBuff = NULL;
- int ret = MS6000_RET_FILE_ACCESS_FAILED;
- if(mfs_i2c_read_single_reg(0x21,&OldFwVersion) == true){ //在此之前,TP的供电及初始化一定要有,否则读不出来
- NewFwVersion = ms6000_GetLibVer();
- printk("mfs6000 OldFwVersion is %d,and NewFwVersion is %d \r\n",OldFwVersion,NewFwVersion);
- }
- i2c_client->addr = MS6000_8BIT_DOWNLOAD_ADDR; //变换成TP的升级I2C地址
- if(NewFwVersion != OldFwVersion){ //如果版本号不同就升级
- ptrBuff = MS6000CTPM_FW;
- nBinary_length = sizeof(MS6000CTPM_FW);
- //download process
- printk("start download \r\n");
- mtk_wdt_disable();
- ret = ms6000_download(ptrBuff,nBinary_length);
- mtk_wdt_get_en_setting(); //升级前后必须有禁止WDT和使能WDT的动作,否则易重启
- //check process
- }
- else{ //如果版本号相同则不动作
- printk("because of the same lib, update abort!\r\n");
- }
- return ret;
- }
- //如下是TPD_RROBE中的改动
- {
- mt65xx_eint_mask(CUST_EINT_touch_PANEL_NUM); //mask TP中断
- int UpResult;
- UpResult = ms6000_firmware_upgrade();
- if(UpResult== MS6000_RET_SUCCESS)
- printk("MFS6000 DOWNLOAD SUCCESS \r\n");
- else
- mfs6000_print_fail_result(UpResult);
- i2c_client->addr = MS6000_8BIT_I2CADDR; //恢复TP的正常操作时I2C地址
- mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_SCL);
- mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_SDA); //恢复I2C功能脚
- mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); //unmask TP中断
- }