/* * Privileged & confidential All Rights/Copyright Reserved by FocalTech. * ** Source code released bellows and hereby must be retained as * FocalTech's copyright and with the following disclaimer accepted by * Receiver. * * "THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO * EVENT SHALL THE FOCALTECH'S AND ITS AFFILIATES'DIRECTORS AND OFFICERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." */ /***************************************************************************** * Some descriptions about this sample code. * fts_fwupg_auto_upgrade() is entry of this sample code. * * The initial work you should do is to implement the i2c communication function based on your platform: * platform_i2c_write() and platform_i2c_read(). * * * How to use the upgrade sample code? * Firstly, Place firmware file(app.i) into firmware directory. * Secondly, modify variable fw_file_ft3x68 to include firmware file you put into firmware directory. * Warning: you can ignore the above steps if you want get firmware file as your way. And * you should get firmware at the beginning of function fts_fwupg_auto_upgrade(). * Thirdly, call fts_fwupg_auto_upgrade(). * * *****************************************************************************/ /***************************************************************************** * Included header files *****************************************************************************/ #include "tp_drv_upgrade.h" #include "tp_port_ctrl.h" #include "sys_config.h" #include #include #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_tp_log_i(__VA_ARGS__) //一般信息打印宏控制 #define static_print_warn(...) sys_tp_log_w(__VA_ARGS__) //警告信息打印一般常开 #define static_print_debug(...) sys_tp_log_d(__VA_ARGS__) //警告信息打印一般常开 #define static_print_error(...) sys_tp_log_e(__VA_ARGS__) //错误信息打印一般常开 #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #endif /***************************************************************************** * Private constant and macro definitions using #define *****************************************************************************/ /*command*/ #define FTS_CMD_RESET 0x07 #define FTS_CMD_FLASH_MODE 0x09 #define FTS_FLASH_MODE_UPGRADE_VALUE 0x0B #define FTS_CMD_FLASH_STATUS 0x6A #define FTS_CMD_ERASE_APP 0x61 #define FTS_RETRIES_REASE 50 #define FTS_RETRIES_DELAY_REASE 400 #define FTS_CMD_FLASH_STATUS_ERASE_OK 0xF0AA #define FTS_CMD_FLASH_STATUS_ECC_OK 0xF055 #define FTS_CMD_ECC_INIT 0x64 #define FTS_CMD_ECC_CAL 0x65 #define FTS_CMD_ECC_READ 0x66 #define FTS_CMD_ECC_CAL_LEN 6 #define FTS_RETRIES_ECC_CAL 10 #define FTS_RETRIES_DELAY_ECC_CAL 50 #define FTS_CMD_WRITE 0xBF #define FTS_RETRIES_WRITE 100 #define FTS_CMD_READ_DELAY 1 #define FTS_CMD_APP_DATA_LEN 0x7A #define FTS_CMD_FW_START_ADDRESS 0x0C00 /*register address*/ #define FTS_UPGRADE_AA 0xAA #define FTS_UPGRADE_55 0x55 #define FTS_RETRIES_CHECK_ID 20 #define FTS_DELAY_UPGRADE_AA 10 #define FTS_DELAY_UPGRADE_RESET 400 #define FTS_DELAY_READ_ID 20 #define FTS_DELAY_UPGRADE 80 #define FTS_RETRIES_UPGRADE 2 #define FTS_MIN_LEN 0x120 #define FTS_MAX_LEN_APP (64 * 1024) #define FTS_VER_IN_FILE_ADDR 0x010A /*Defined Macroes*/ #define FTS_FLASH_PACKET_LENGTH (128) #define FTS_MAX_LEN_ECC_CALC (0xFFFE) /* must be even */ /***************************************************************************** * Private variables/functions *****************************************************************************/ static bool tp_fw_valid = false;/*to note firmware in TP controller is valid or not*/ /* The array variable fw_file_ft3x68 stores the firmware file that you * want to upgrade. * Please modify it based on the firmware file you get. * Please ignore it if you get firmware file from file system, now you * need read firmware file using your method. */ uint8_t fw_file_ft3x68[] = { #include "FT3X68_20240415_app.i" }; #ifndef FT6146_I2C_ADDR #define FT6146_I2C_ADDR 0x38 #endif static uint32_t ft6146_i2c_write(uint8_t cmd) { return tp_i2c_cmd_write(FT6146_I2C_ADDR, cmd); } static uint32_t ft6146_i2c_read(uint8_t reg_addr, uint8_t *data_buf, uint32_t data_len) { return tp_i2c_data_read(FT6146_I2C_ADDR, reg_addr, 1, data_buf, data_len); } static uint32_t ft6146_reg_write(uint8_t reg_addr, uint8_t reg_cfg) { return tp_i2c_reg_write(FT6146_I2C_ADDR, reg_addr, 1, reg_cfg); } static uint32_t ft6146_data_write(uint8_t reg_addr, uint8_t *data_buf, uint32_t data_len) { return tp_i2c_data_write(FT6146_I2C_ADDR, reg_addr, data_buf, data_len); } /*Functions*/ /************************************************************************ * Name: fts_fwupg_check_flash_status * Brief: * read status from tp * Input: @flash_status: correct value from tp * @retries: read retry times * @retries_delay: retry delay * Output: * Return: * return true if flash status check pass, otherwise return false ***********************************************************************/ static bool fts_fwupg_check_flash_status(uint16_t flash_status, int retries, int retries_delay) { int ret = 0; int i = 0; uint8_t cmd = 0; uint8_t val[2] = { 0 }; uint16_t read_status = 0; for (i = 0; i < retries; i++) { cmd = FTS_CMD_FLASH_STATUS; ret = ft6146_i2c_read(cmd , val, 2); read_status = (((uint16_t)val[0]) << 8) + val[1]; if (flash_status == read_status) { /* static_print_debug("[UPGRADE]flash status ok"); */ return true; } /* static_print_debug("flash status fail,ok:%04x read:%04x, retries:%d", flash_status, read_status, i); */ tp_delay(retries_delay); } return false; } /***************************************************************************** * Name: fts_check_id * Brief: * The function is used to check id. * Input: * Output:@id_h, id chiper high * @id_l, id chiper low * Return: * return 0 if check id successfully, otherwise error code. *****************************************************************************/ static int fts_check_id(uint8_t id_h, uint8_t id_l) { int i = 0; uint8_t cmd = FTS_CMD_READ_ID; uint8_t buf[2] = { 0 }; cmd = 0xC0; ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_AA); ft6146_i2c_read(cmd, buf, 2); static_print_info("TOUCH: cmd:%x %x", buf[0], buf[1]); ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_55); ft6146_i2c_read(cmd, buf, 2); static_print_info("TOUCH: cmd:%x %x", buf[0], buf[1]); tp_delay(FTS_DELAY_UPGRADE); /*confirm in boot*/ for (i = 0; i < FTS_RETRIES_CHECK_ID; i++) { ft6146_reg_write(FTS_UPGRADE_55, FTS_UPGRADE_AA); tp_delay(FTS_DELAY_UPGRADE_AA); cmd = FTS_CMD_READ_ID; ft6146_i2c_read(cmd, buf, 2); if ((buf[0] != id_h) || (buf[1] != id_l)) { static_print_error("TOUCH: check id fail,read id:0x%02x%02x != 0x%02x%02x,retry:%d", buf[0], buf[1], id_h, id_l, i); return -1; } else break; ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_AA); ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_55); tp_delay(FTS_DELAY_READ_ID); } if (i >= 10) return -1; static_print_info("TOUCH: read boot id:%x %x", buf[0], buf[1]); return 0; } /************************************************************************ * Name: fts_fwupg_enter_into_boot * Brief: * enter into boot environment, ready for upgrade * Input: * Output: * Return: * return 0 if success, otherwise return error code ***********************************************************************/ static int fts_fwupg_enter_into_boot(void) { int ret = 0; uint8_t boot_id[2] = { 0 }; /*software reset to boot mode*/ if (tp_fw_valid) { ret = ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_AA); if (ret < 0) { static_print_error("TOUCH: write FC=0xAA fail"); return ret; } tp_delay(FTS_DELAY_UPGRADE_AA); ret = ft6146_reg_write(FTS_REG_UPGRADE, FTS_UPGRADE_55); if (ret < 0) { static_print_error("TOUCH: write FC=0x55 fail"); return ret; } tp_delay(FTS_DELAY_UPGRADE); } /*confirm TP controller is int romboot state*/ ret = fts_check_id(FTS_CHIP_IDH, FTS_CHIP_IDL); if (ret < 0) { static_print_error("TOUCH: checking id fails"); return -1; } return 0; } /************************************************************************ * Name: fts_fwupg_erase * Brief: * erase flash area * Input: @delay: delay after erase * Output: * Return: * return 0 if success, otherwise return error code ***********************************************************************/ static int fts_fwupg_erase(uint32_t delay) { int ret = 0; uint8_t cmd = 0; bool flag = false; static_print_info("**********erase now**********"); /*send to erase flash*/ cmd = FTS_CMD_ERASE_APP; ret = ft6146_i2c_write(cmd); if (ret < 0) { static_print_error("TOUCH: erase cmd fail"); return ret; } tp_delay(delay); /* read status 0xF0AA: success */ flag = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ERASE_OK, FTS_RETRIES_REASE, FTS_RETRIES_DELAY_REASE); if (!flag) { static_print_error("TOUCH: ecc flash status check fail"); return -1; } return 0; } /************************************************************************ * Name: fts_flash_write_buf * Brief: * write buf data to flash address * Input: @saddr: start address data write to flash * @buf: data buffer * @len: data length * @delay: delay after write * Output: * Return: * return 0 if success, otherwise return error code ***********************************************************************/ static int fts_flash_write_buf(uint32_t saddr, uint8_t *buf, uint16_t len, uint32_t delay) { int ret = 0; uint32_t i = 0; uint32_t j = 0; uint32_t packet_number = 0; uint16_t packet_len = 0; uint32_t addr = 0; uint32_t offset = 0; uint16_t remainder = 0; uint8_t packet_buf[FTS_FLASH_PACKET_LENGTH+6] = {0}; uint8_t cmd = 0; uint8_t val[2] = { 0 }; uint16_t read_status = 0; uint16_t wr_ok = 0; if (!buf || !len) { static_print_error("TOUCH: buf/len is invalid"); return -1; } static_print_info("TOUCH: data buf start addr=0x%x, len=0x%x", saddr, len); packet_number = len / FTS_FLASH_PACKET_LENGTH; remainder = len % FTS_FLASH_PACKET_LENGTH; if (remainder > 0) packet_number++; packet_len = FTS_FLASH_PACKET_LENGTH; static_print_info("TOUCH: write data, num:%d remainder:%d", packet_number, remainder); for (i = 0; i < packet_number; i++) { offset = i * FTS_FLASH_PACKET_LENGTH; addr = saddr + offset; packet_buf[0] = FTS_CMD_WRITE; packet_buf[1] = (addr >> 16); packet_buf[2] = (addr >> 8); packet_buf[3] = (addr); /* last packet */ if ((i == (packet_number - 1)) && remainder) packet_len = remainder; packet_buf[4] = (packet_len >> 8); packet_buf[5] = (packet_len); memcpy(&packet_buf[6],(buf+offset),packet_len); ret = ft6146_data_write(packet_buf[0], &packet_buf[1], (packet_len + 5)); if (ret < 0) { static_print_error("TOUCH: app write fail"); return ret; } tp_delay(FTS_CMD_READ_DELAY); /* read status */ wr_ok = 0x1000 + addr / packet_len; for (j = 0; j < FTS_RETRIES_WRITE; j++) { cmd = FTS_CMD_FLASH_STATUS; ret = ft6146_i2c_read(cmd, val, 2); read_status = (((uint16_t)val[0]) << 8) + val[1]; if (wr_ok == read_status) break; else static_print_debug("%x %x", wr_ok, read_status); tp_delay(FTS_CMD_READ_DELAY); } } return 0; } /************************************************************************ * Name: fts_fwupg_ecc_cal_host * Brief: * Calculate the ecc value of firmware program. * Input: @data: pointer to firmware program * @data_len: length of firmware program * @ecc_value: store ecc value * Output: * Return: * ecc value calculated in host using XOR8 algorithm ***********************************************************************/ static int fts_ecc_cal_host(const uint8_t *data, uint32_t data_len) { uint8_t ecc = 0; uint32_t i = 0; for (i = 0; i < data_len; i++ ) { ecc ^= data[i]; } return ecc; } /************************************************************************ * Name: fts_fwupg_ecc_cal * Brief: * calculate and get ecc from tp * Input: @saddr: start address need calculate ecc * @len: length need calculate ecc * Output: * Return: * return data ecc of tp if success, otherwise return error code ***********************************************************************/ static int fts_fwupg_ecc_tp(uint32_t saddr, uint16_t len) { int ret = 0; uint8_t wbuf[7] = { 0 }; uint8_t val[2] = { 0 }; bool bflag = false; uint8_t cmd = 0; uint8_t regaddr = 0; uint32_t packet_num = 0; uint32_t packet_len = 0; uint32_t remainder = 0; /* check sum init */ cmd = FTS_CMD_ECC_INIT; ret = ft6146_i2c_write(cmd); if (ret < 0) { static_print_error("TOUCH: ecc init cmd write fail"); return ret; } packet_num = len / FTS_MAX_LEN_ECC_CALC; remainder = len % FTS_MAX_LEN_ECC_CALC; if (remainder) packet_num++; packet_len = FTS_MAX_LEN_ECC_CALC; for(uint32_t i=0;i < packet_num; i++){ /* send commond to start checksum */ wbuf[0] = FTS_CMD_ECC_CAL; wbuf[1] = (saddr >> 16); wbuf[2] = (saddr >> 8); wbuf[3] = (saddr); wbuf[4] = (len >> 8); wbuf[5] = (len ); static_print_debug("ecc calc startaddr:0x%04x, len:%d", saddr, len); ret = ft6146_data_write(wbuf[0], &wbuf[1] , (FTS_CMD_ECC_CAL_LEN - 1)); if (ret < 0) { static_print_error("TOUCH: ecc calc cmd write fail"); return ret; } tp_delay(len / 256); /* read status if check sum is finished */ bflag = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ECC_OK, FTS_RETRIES_ECC_CAL, FTS_RETRIES_DELAY_ECC_CAL); if (!bflag) { static_print_error("TOUCH: ecc flash status read fail"); return -1; } } /* read out check sum */ regaddr = FTS_CMD_ECC_READ; ret = ft6146_i2c_read(regaddr, val, 1); if (ret < 0) { static_print_error( "TOUCH: ecc read cmd write fail"); return ret; } return (val[0]); } /***************************************************************************** * Name: fts_ft3x68_upgrade * Brief: * Main flow of FT3x68 firmware upgrade. * Input: @fw_file: firmware file buffer * @fw_file_size: firmware file size * Output: * Return: * Error code if upgrade fails, 0 if success. *****************************************************************************/ static int fts_ft3x68_upgrade(uint8_t *fw_file, uint32_t fw_file_size) { int ret = 0; uint8_t rst_cmd = FTS_CMD_RESET; uint8_t cmd[4] = { 0 }; uint8_t *firmware; uint32_t firmware_size; uint32_t start_address = 0; int ecc_in_host = 0; int ecc_in_tp = 0; if (!fw_file || (fw_file_size < FTS_MIN_LEN) || (fw_file_size > (37 * 1024))) { static_print_error("TOUCH: fw file is null, or fw file size(%d) is invalid", fw_file_size); return -1; } /*get firmware data*/ firmware = fw_file; firmware_size = fw_file_size; /*enter into boot environment*/ ret = fts_fwupg_enter_into_boot(); if (ret < 0) { static_print_error("TOUCH: enter into boot fails"); goto err_upgrade; } #if 0 /*send firmware size*/ cmd[0] = FTS_CMD_APP_DATA_LEN; cmd[1] = (firmware_size >> 16); cmd[2] = (firmware_size >> 8); cmd[3] = (firmware_size); ret = ft6146_data_write(cmd[0], &cmd[1], 3); if (ret < 0) { static_print_error("TOUCH: write 7A fails"); return ret; } #endif /*Erase firmware part in flash*/ ret = ft6146_reg_write(FTS_CMD_FLASH_MODE, FTS_FLASH_MODE_UPGRADE_VALUE); if (ret < 0) { static_print_error("TOUCH: upgrade mode(09) cmd write fail"); goto err_upgrade; } ret = fts_fwupg_erase(60 * (firmware_size / 4096)); if (ret < 0) { static_print_error("TOUCH: erase cmd write fail"); goto err_upgrade; } /*write firmware data into flash*/ start_address = FTS_CMD_FW_START_ADDRESS; ret = fts_flash_write_buf(start_address, firmware, firmware_size, 1); if (ret < 0 ) { static_print_error("TOUCH: write buffer to flash fail"); goto err_upgrade; } ecc_in_host = fts_ecc_cal_host(firmware, firmware_size); ecc_in_tp = fts_fwupg_ecc_tp(start_address, firmware_size); static_print_info("TOUCH: ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host); if (ecc_in_tp != ecc_in_host) { static_print_error("TOUCH: ecc check fail"); goto err_upgrade; } static_print_info("TOUCH: upgrade success, reset to normal boot"); ret = ft6146_i2c_write(rst_cmd); if (ret < 0) { static_print_error("TOUCH: reset to normal boot fail"); } tp_delay(FTS_DELAY_UPGRADE_RESET); return 0; err_upgrade: ret = ft6146_i2c_write(rst_cmd); if (ret < 0) { static_print_error("TOUCH: reset to normal boot fail"); } return -1; } /***************************************************************************** * Name: fts_fwupg_check_fw_valid * Brief: * To check firmware in TP controller is valid or not. * Input: * Output: * Return: * true: fw is valid, false: fw is invalid *****************************************************************************/ static bool fts_fwupg_check_fw_valid(void) { int ret = 0; int i = 0; uint8_t id = 0xFF; do { /*loop to read ID because some time is needed for TP controller initialization*/ ret = ft6146_i2c_read(FTS_REG_CHIP_ID, &id, 1); if (id == FTS_CHIP_IDH) { static_print_debug("TOUCH: TP Ready,Device ID:0x%02x", id); return true; } else { static_print_debug("TOUCH: TP Not Ready,Read:0x%02x,ret:%d", id, ret); } tp_delay(INTERVAL_READ_REG); } while (i++ < 5); return false; } /***************************************************************************** * Name: fts_fwupg_need_upgrade * Brief: * To check firmware upgrade is needed or not. Host need upgrade firmware in * the following situations(one of them): * a. firwmare in TP controller is invalid. * b. firmware versions in TP controller and host are different. * Input: @fw_file: firmware file buffer * @fw_file_size: firmware file size * Output: * Return: * true: firmware upgrade is needed, false: not needed *****************************************************************************/ static bool fts_fwupg_need_upgrade(uint8_t *fw_file, uint32_t fw_file_size) { int ret = 0; uint8_t fw_ver_in_host = 0; uint8_t fw_ver_in_tp = 0; if (!tp_fw_valid) { static_print_debug("TOUCH: firmware in TP controller is invalid, need upgrade"); return true; } ret = ft6146_i2c_read(FTS_REG_FW_VER, &fw_ver_in_tp, 1); if (ret < 0) { static_print_error("TOUCH: read firmware version from reg0xA6 fals"); return false; } if (fw_file_size > FTS_MIN_LEN) fw_ver_in_host = fw_file[FTS_VER_IN_FILE_ADDR]; static_print_info("TOUCH: fw version in tp:%x, host:%x", fw_ver_in_tp, fw_ver_in_host); if (fw_ver_in_tp != fw_ver_in_host) { return true; } return false; } /***************************************************************************** * Name: fts_fwupg_upgrade * Brief: * The whole flow of firmware upgrade. * Input: @fw_file: firmware file buffer * @fw_file_size: firmware file size * Output: * Return: * Error code if upgrade fails, 0 if success. *****************************************************************************/ static int fts_fwupg_upgrade(uint8_t *fw_file, uint32_t fw_file_size) { int ret = 0; bool upgrade_flag = false; uint8_t fw_ver = 0; uint8_t upgrade_count = 0; /*check firmware upgrade is needed or not*/ upgrade_flag = fts_fwupg_need_upgrade(fw_file, fw_file_size); static_print_info("TOUCH: fw upgrade flag:%d", upgrade_flag); if (upgrade_flag) { do { upgrade_count++; ret = fts_ft3x68_upgrade(fw_file, fw_file_size); if (ret >= 0) { ft6146_i2c_read(FTS_REG_FW_VER, &fw_ver, 1); static_print_info("TOUCH: success upgrade to fw version %02x", fw_ver); break; } } while (upgrade_count < FTS_RETRIES_UPGRADE); } return ret; } /***************************************************************************** * Name: fts_fwupg_auto_upgrade * Brief: * firmware auto upgrade. * Input: * Output: * Return: * Error code if auto upgrade fails, 0 if success. *****************************************************************************/ int fts_fwupg_auto_upgrade(void) { int ret = 0; uint8_t *fw_file = fw_file_ft3x68; uint32_t fw_file_size = sizeof(fw_file_ft3x68); static_print_info("********************auto upgrade********************"); /* Get firmware file, and check firmware size * we use all.i as an example(variable fw_file_ft3x68 stores the firmware). * You should read it if you use all.bin */ if (!fw_file || (fw_file_size < FTS_MIN_LEN)) { static_print_error("TOUCH: fw_file is null, or firmare file size(%d) is invalid", fw_file_size); return -1; } /*check firmware is valid or not*/ tp_fw_valid = fts_fwupg_check_fw_valid(); if (!tp_fw_valid) { static_print_debug("TOUCH: firmware in flash is invalid"); } /******run firmware upgrade flow******/ ret = fts_fwupg_upgrade(fw_file, fw_file_size); if (ret < 0){ static_print_error("**********tp fw upgrade fails**********"); }else{ static_print_info("**********tp fw no upgrade/upgrade success**********"); } return ret; }