#include #include #include #include #include #include #include #include #include #include #include "fts_ts.h" #define WRITE_CHUNK_SIZE 64 #define FTS_DEFAULT_UMS_FW "/sdcard/Firmware/TSP/stm.fw" #define FTS_DEFAULT_FFU_FW "ffu_tsp.bin" #define FTS64FILE_SIGNATURE 0xaaaa5555 enum { BUILT_IN = 0, UMS, NONE, FFU, }; struct fts64_header { unsigned int signature; unsigned short fw_ver; unsigned char fw_id; unsigned char reserved1; unsigned char internal_ver[8]; unsigned char released_ver[8]; unsigned int reserved2; unsigned int checksum; }; static int fts_fw_wait_for_flash_ready(struct fts_ts_info *info) { unsigned char regAdd; unsigned char buf[3]; int retry = 0; regAdd = FTS_CMD_READ_FLASH_STAT; while (info->fts_read_reg (info, ®Add, 1, (unsigned char *)buf, 1)) { if ((buf[0] & 0x01) == 0) break; if (retry++ > FTS_RETRY_COUNT * 10) { tsp_debug_err(true, info->dev, "%s: Time Over\n", __func__); return -FTS_ERROR_TIMEOUT; } msleep(20); } return 0; } #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD static bool get_PureAutotune_status(struct fts_ts_info *info) { int rc; unsigned char regAdd[3]; unsigned char buf[5]; bool retVal = false; regAdd[0] = 0xd0; regAdd[1] = 0x00; regAdd[2] = 0x58; /* regAdd[0] = 0xb3; regAdd[1] = 0x00; regAdd[2] = 0x01; info->fts_write_reg(info, regAdd, 3); fts_delay(1); regAdd[0] = 0xb1; regAdd[1] = 0xFF; regAdd[2] = 0xE0; */ rc = info->fts_read_reg(info, regAdd, 3, buf, 4); if (!rc) { tsp_debug_info(true, info->dev, "%s: PureAutotune Information Read Fail!! [Data : %2X%2X]\n", __func__, buf[1], buf[2]); return rc; } if((buf[1] == 0xA5) && (buf[2] == 0x96)) retVal = true; tsp_debug_info(true, info->dev, "%s: PureAutotune Information !! [Data : %2X%2X]\n", __func__, buf[1], buf[2]); return retVal; } static bool get_AFE_status(struct fts_ts_info *info) { int rc; unsigned char regAdd[3]; unsigned char buf[5]; bool retVal = false; regAdd[0] = 0xd0; regAdd[1] = 0x00; regAdd[2] = 0x5A; rc = info->fts_read_reg(info, regAdd, 3, buf, 4); if (!rc) { tsp_debug_info(true, info->dev, "%s: Read Fail - Final AFE [Data : %2X] AFE Ver [Data : %2X] \n", __func__, buf[1], buf[2]); return rc; } if( buf[1] ) retVal = true; tsp_debug_info(true, info->dev, "%s: Final AFE [Data : %2X] AFE Ver [Data : %2X] \n", __func__, buf[1], buf[2]); return retVal; } #endif #define FW_IMAGE_SIZE_D1 (64 * 1024) #define FW_IMAGE_SIZE_D2 (128 * 1024) #define SIGNEDKEY_SIZE 256 #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD #define FW_CX_AREA_SIZE (4 * 1024) #endif //TEST int FTS_Check_DMA_Done(struct fts_ts_info *info) { int timeout = 60; // 3 sec timeout unsigned char regAdd[2] = { 0xF9, 0x05}; unsigned char val[1]; int cnt = 0; cnt = 0; do { info->fts_read_reg(info, ®Add[0], 2, (unsigned char*)val, 1); if ( (val[0] & 0x80) != 0x80) { break; } msleep(50); timeout--; }while(timeout != 0); if (timeout == 0) { return -1; } return 0; } static int fts_fw_burn(struct fts_ts_info *info, unsigned char *fw_data) { unsigned char regAdd[WRITE_CHUNK_SIZE + 3]; int section; int fsize = FW_IMAGE_SIZE_D1; bool needPartialDownload = false; #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD needPartialDownload = get_PureAutotune_status(info); if (needPartialDownload){ /* Reset FTS */ info->fts_systemreset(info); /* wait for ready event */ info->fts_wait_for_ready(info); } #endif tsp_debug_info(true, info->dev, "%s: start, PartialDownload is %s\n", __func__, needPartialDownload ? "Enabled" : "Disabled"); /* Check busy Flash */ if (fts_fw_wait_for_flash_ready(info) < 0) return -FTS_ERROR_TIMEOUT; /* FTS_CMD_UNLOCK_FLASH */ tsp_debug_info(true, info->dev, "%s: Unlock Flash\n", __func__); regAdd[0] = FTS_CMD_UNLOCK_FLASH; regAdd[1] = 0x74; regAdd[2] = 0x45; info->fts_write_reg(info, ®Add[0], 3); msleep(500); /* Copy to PRAM */ if (info->digital_rev == FTS_DIGITAL_REV_2) { fsize = FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header); #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD if (needPartialDownload) fsize = fsize - FW_CX_AREA_SIZE; #endif } tsp_debug_info(true, info->dev, "%s: Copy to PRAM [Size : %d]\n", __func__, fsize); for (section = 0; section < (fsize / WRITE_CHUNK_SIZE); section++) { regAdd[0] = FTS_CMD_WRITE_PRAM + (((section * WRITE_CHUNK_SIZE) >> 16) & 0x0f); regAdd[1] = ((section * WRITE_CHUNK_SIZE) >> 8) & 0xff; regAdd[2] = (section * WRITE_CHUNK_SIZE) & 0xff; memcpy(®Add[3], &fw_data[section * WRITE_CHUNK_SIZE + sizeof(struct fts64_header)], WRITE_CHUNK_SIZE); info->fts_write_reg(info, ®Add[0], WRITE_CHUNK_SIZE + 3); } msleep(100); /* Erase Program Flash */ tsp_debug_info(true, info->dev, "%s: Erase Program Flash\n", __func__); info->fts_command(info, FTS_CMD_ERASE_PROG_FLASH); msleep(100); /* Check busy Flash */ if (fts_fw_wait_for_flash_ready(info) < 0) return -FTS_ERROR_TIMEOUT; /* Burn Program Flash */ tsp_debug_info(true, info->dev, "%s: Burn Program Flash\n", __func__); info->fts_command(info, FTS_CMD_BURN_PROG_FLASH); msleep(100); /* Check busy Flash */ if (fts_fw_wait_for_flash_ready(info) < 0) return -FTS_ERROR_TIMEOUT; /* Reset FTS */ info->fts_systemreset(info); return 0; } //TEST static int fts_fw_burn_stm7(struct fts_ts_info *info, unsigned char *fw_data) { int rc; const unsigned long int FTS_TOTAL_SIZE = (256 * 1024); // Total 256kB const unsigned long int DRAM_LEN = (64 * 1024); // 64KB const unsigned int CODE_ADDR_START = 0x0000; const unsigned int WRITE_CHUNK_SIZE_D3 = 32; unsigned long int size = 0; unsigned long int i; unsigned long int j; unsigned long int k; unsigned long int dataLen; unsigned int len = 0; unsigned int writeAddr = 0; unsigned char buf[WRITE_CHUNK_SIZE_D3 + 3]; unsigned char regAdd[8] = {0}; int cnt; //==================== System reset ==================== //System Reset ==> F7 52 34 regAdd[0] = 0xF7; regAdd[1] = 0x52; regAdd[2] = 0x34; info->fts_write_reg(info, ®Add[0], 3); msleep(200); //==================== Unlock Flash ==================== //Unlock Flash Command ==> F7 74 45 regAdd[0] = 0xF7; regAdd[1] = 0x74; regAdd[2] = 0x45; info->fts_write_reg(info, ®Add[0], 3); msleep(100); //==================== Unlock Erase Operation ==================== regAdd[0] = 0xFA; regAdd[1] = 0x72; regAdd[2] = 0x01; info->fts_write_reg(info, ®Add[0], 3); msleep(100); //==================== Erase full Flash ==================== regAdd[0] = 0xFA; regAdd[1] = 0x02; regAdd[2] = 0xC0; info->fts_write_reg(info, ®Add[0], 3); msleep(100); //==================== Unlock Programming operation ==================== regAdd[0] = 0xFA; regAdd[1] = 0x72; regAdd[2] = 0x02; info->fts_write_reg(info, ®Add[0], 3); //========================== Write to FLASH ========================== i = 0; k = 0; size = FTS_TOTAL_SIZE; while(i < size) { j = 0; dataLen = size - i; while ((j < DRAM_LEN) && (j < dataLen)) //DRAM_LEN = 64*1024 { writeAddr = (unsigned int)(j & 0xFFFF); cnt = 0; buf[cnt++] = 0xF8; buf[cnt++] = (writeAddr >> 8) & 0xFF; buf[cnt++] = (writeAddr >> 0) & 0xFF; memcpy(&buf[cnt], &fw_data[sizeof(struct fts64_header) + i], WRITE_CHUNK_SIZE_D3); cnt += WRITE_CHUNK_SIZE_D3; info->fts_write_reg(info, &buf[0], cnt); i += WRITE_CHUNK_SIZE_D3; j += WRITE_CHUNK_SIZE_D3; } tsp_debug_info(true, info->dev, "%s: Write to Flash - Total %ld bytes\n", __func__, i); //===================configure flash DMA===================== len = j / 4 - 1; // 64*1024 / 4 - 1 buf[0] = 0xFA; buf[1] = 0x06; buf[2] = 0x00; buf[3] = 0x00; buf[4] = (CODE_ADDR_START +( (k * DRAM_LEN) >> 2)) & 0xFF; // k * 64 * 1024 / 4 buf[5] = (CODE_ADDR_START + ((k * DRAM_LEN) >> (2+8))) & 0xFF; // k * 64 * 1024 / 4 / 256 buf[6] = (len >> 0) & 0xFF; //DMA length in word buf[7] = (len >> 8) & 0xFF; //DMA length in word buf[8] = 0x00; info->fts_write_reg(info, &buf[0], 9); msleep(100); //===================START FLASH DMA===================== buf[0] = 0xFA; buf[1] = 0x05; buf[2] = 0xC0; info->fts_write_reg(info, &buf[0], 3); rc = FTS_Check_DMA_Done(info); if (rc < 0) { return rc; } k++; } tsp_debug_info(true, info->dev, "%s : Total write %ld kbytes \n", __func__, i / 1024); //==================== System reset ==================== //System Reset ==> F7 52 34 regAdd[0] = 0xF7; regAdd[1] = 0x52; regAdd[2] = 0x34; info->fts_write_reg(info, ®Add[0],3); return 0; } static int fts_get_system_status(struct fts_ts_info *info, unsigned char *val1, unsigned char *val2) { bool rc = -1; unsigned char regAdd1[4] = { 0xb2, 0x07, 0xfb, 0x04 }; unsigned char regAdd2[4] = { 0xb2, 0x17, 0xfb, 0x04 }; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; if (info->digital_rev == FTS_DIGITAL_REV_2) { regAdd2[1] = 0x1f; } else if (info->digital_rev == FTS_DIGITAL_REV_3) { /* Mutual Tune Version - Config area */ regAdd1[1] = 0x07; regAdd1[2] = 0x31; /* Mutual Tune Version - Info0 area */ regAdd2[1] = 0x10; regAdd2[2] = 0x00; } info->fts_write_reg(info, ®Add1[0], 4); info->fts_write_reg(info, ®Add2[0], 4); memset(data, 0x0, FTS_EVENT_SIZE); regAdd1[0] = READ_ONE_EVENT; while (info->fts_read_reg(info, ®Add1[0], 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if ((data[0] == 0x12) && (data[1] == regAdd1[1]) && (data[2] == regAdd1[2])) { rc = 0; *val1 = data[3]; tsp_debug_info(true, info->dev, "%s: System Status 1 : 0x%02x, retry=%d\n", __func__, data[3], retry); } else if ((data[0] == 0x12) && (data[1] == regAdd2[1]) && (data[2] == regAdd2[2])) { rc = 0; *val2 = data[3]; tsp_debug_info(true, info->dev, "%s: System Status 2 : 0x%02x, retry=%d\n", __func__, data[3], retry); break; } if (retry++ > FTS_RETRY_COUNT * 10) { rc = -1; tsp_debug_err(true, info->dev, "%s: Time Over\n", __func__); break; } } return rc; } int fts_fw_wait_for_event(struct fts_ts_info *info, unsigned char eid) { int rc; unsigned char regAdd; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; memset(data, 0x0, FTS_EVENT_SIZE); regAdd = READ_ONE_EVENT; rc = -1; while (info->fts_read_reg(info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if (data[0] == EVENTID_STATUS_EVENT || data[0] == EVENTID_ERROR) { if ((data[0] == EVENTID_STATUS_EVENT) && (data[1] == eid)) { rc = 0; break; } else { tsp_debug_info(true, info->dev, "%s: %2X,%2X,%2X,%2X \n", __func__, data[0],data[1],data[2],data[3]); } } if (retry++ > FTS_RETRY_COUNT * 15) { rc = -1; tsp_debug_info(true, info->dev, "%s: Time Over ( %2X,%2X,%2X,%2X )\n", __func__, data[0],data[1],data[2],data[3]); break; } msleep(20); } return rc; } static int fts_fw_wait_for_event_D3(struct fts_ts_info *info, unsigned char eid0, unsigned char eid1) { int rc; unsigned char regAdd; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; memset(data, 0x0, FTS_EVENT_SIZE); regAdd = READ_ONE_EVENT; rc = -1; while (info->fts_read_reg (info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if (data[0] == EVENTID_STATUS_EVENT || data[0] == EVENTID_ERROR) { if ((data[0] == EVENTID_STATUS_EVENT) && (data[1] == eid0) && (data[2] == eid1)) { rc = 0; break; } else { tsp_debug_info(true, info->dev, "%s: %2X,%2X,%2X,%2X \n", __func__, data[0], data[1], data[2], data[3]); } } if (retry++ > FTS_RETRY_COUNT * 15) { rc = -1; tsp_debug_info(true, info->dev, "%s: Time Over ( %2X,%2X,%2X,%2X )\n", __func__, data[0], data[1], data[2], data[3]); break; } msleep(20); } return rc; } int fts_fw_wait_for_specific_event(struct fts_ts_info *info, unsigned char eid0, unsigned char eid1, unsigned char eid2) { int rc; unsigned char regAdd; unsigned char data[FTS_EVENT_SIZE]; int retry = 0; memset(data, 0x0, FTS_EVENT_SIZE); regAdd = READ_ONE_EVENT; rc = -1; while (info->fts_read_reg(info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { if (data[0]) { if ((data[0] == eid0) && (data[1] == eid1) && (data[2] == eid2)) { rc = 0; break; } else { tsp_debug_info(true, info->dev, "%s: %2X,%2X,%2X,%2X \n", __func__, data[0], data[1], data[2], data[3]); } } if (retry++ > FTS_RETRY_COUNT * 15) { rc = -1; tsp_debug_info(true, info->dev, "%s: Time Over ( %2X,%2X,%2X,%2X )\n", __func__, data[0], data[1], data[2], data[3]); break; } msleep(20); } return rc; } void fts_execute_autotune(struct fts_ts_info *info) { #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD int ret = 0; unsigned char regData[4]; // {0xC1, 0x0E}; #endif #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD bool bFinalAFE = false; bool NoNeedAutoTune = false; // default for factory bFinalAFE = get_AFE_status(info); #if !defined (CONFIG_SEC_FACTORY) NoNeedAutoTune = get_PureAutotune_status(info); // Check flag and decide cx_tune #endif tsp_debug_info(true, info->dev, "%s: AFE(%d), NoNeedAutoTune(%d)\n", __func__,bFinalAFE, NoNeedAutoTune); if ((!NoNeedAutoTune) || (info->o_afe_ver!=info->afe_ver)) { #endif info->fts_command(info, CX_TUNNING); msleep(300); if (info->stm_ver == STM_VER7) { fts_fw_wait_for_event_D3(info, STATUS_EVENT_MUTUAL_AUTOTUNE_DONE, 0x00); info->fts_command(info, SELF_AUTO_TUNE); msleep(300); fts_fw_wait_for_event_D3(info, STATUS_EVENT_SELF_AUTOTUNE_DONE_D3, 0x00); #ifdef FTS_SUPPORT_WATER_MODE fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_AUTOTUNE_DONE); fts_fw_wait_for_event(info, STATUS_EVENT_SELF_AUTOTUNE_DONE); #endif } else { fts_fw_wait_for_event(info, STATUS_EVENT_MUTUAL_AUTOTUNE_DONE); #ifdef FTS_SUPPORT_WATER_MODE fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_AUTOTUNE_DONE); fts_fw_wait_for_event(info, STATUS_EVENT_SELF_AUTOTUNE_DONE); #endif #ifdef FTS_SUPPORT_SELF_MODE info->fts_command(info, SELF_AUTO_TUNE); msleep(300); fts_fw_wait_for_event(info, STATUS_EVENT_SELF_AUTOTUNE_DONE); #endif } #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD } if (bFinalAFE) { #ifdef CONFIG_SEC_FACTORY tsp_debug_info(true, info->dev, "%s: AFE_status(%d) write ( C1 0E )\n", __func__,bFinalAFE); regData[0] = 0xC1; regData[1] = 0x0E; ret = info->fts_write_reg(info, regData, 2);//write C1 0E if (ret < 0) tsp_debug_info(true, info->dev, "%s: Flash Back up PureAutotune Fail(Set)\n", __func__); msleep(20); fts_fw_wait_for_event(info, STATUS_EVENT_PURE_AUTOTUNE_FLAG_WRITE_FINISH); #else if (NoNeedAutoTune && (info->o_afe_ver!=info->afe_ver)) { tsp_debug_info(true, info->dev, "%s: AFE_status(%d) write ( C2 0E )\n", __func__,bFinalAFE); regData[0] = 0xC2; regData[1] = 0x0E; ret = info->fts_write_reg(info, regData, 2);//Write C2 0E if (ret < 0) tsp_debug_info(true, info->dev, "%s: Flash Back up PureAutotune Fail(Clear)\n", __func__); msleep(20); fts_fw_wait_for_event(info, STATUS_EVENT_PURE_AUTOTUNE_FLAG_ERASE_FINISH); } #endif } else { tsp_debug_info(true, info->dev, "%s: AFE_status(%d) write ( C2 0E )\n", __func__,bFinalAFE); regData[0] = 0xC2; regData[1] = 0x0E; ret = info->fts_write_reg(info, regData, 2);//Write C2 0E if (ret < 0) tsp_debug_info(true, info->dev, "%s: Flash Back up PureAutotune Fail(Clear)\n", __func__); msleep(20); fts_fw_wait_for_event(info, STATUS_EVENT_PURE_AUTOTUNE_FLAG_ERASE_FINISH); } #endif info->fts_command(info, FTS_CMD_SAVE_CX_TUNING); msleep(230); fts_fw_wait_for_event(info, STATUS_EVENT_FLASH_WRITE_CXTUNE_VALUE); if (info->stm_ver == STM_VER7) { info->fts_command(info, FTS_CMD_SAVE_FWCONFIG); msleep(230); fts_fw_wait_for_event(info, STATUS_EVENT_FLASH_WRITE_CONFIG); } #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD /* Reset FTS */ info->fts_systemreset(info); msleep(20); /* wait for ready event */ info->fts_wait_for_ready(info); #endif } #ifdef FTS_SUPPORT_STRINGLIB static void fts_enable_custom_library(struct fts_ts_info *info) { unsigned char EnableCLIB[4] = {0xB0, 0x01, 0x10, 0x77}; if (strncmp(info->dt_data->project, "T", 1) == 0) { if (strncmp(info->dt_data->project, "TB", 2) == 0) EnableCLIB[3] = 0x7D; } else { return; } tsp_debug_info(true, info->dev, "%s\n", __func__); info->fts_write_reg(info, &EnableCLIB[0], 4); } static void fts_check_custom_library(struct fts_ts_info *info) { int rc; unsigned char regAdd[3] = {0xd0, 0x00, 0x50}; unsigned char buf[3]; unsigned char ver = 0; /* string library is seperate by model name in T project * after T project, String library is used all project. */ if (strncmp(info->dt_data->project, "T", 1) != 0) return; rc = info->fts_read_reg(info, regAdd, 3, buf, 2); /* ver = buf[0];*/ ver = buf[1]; tsp_debug_info(true, info->dev, "%s, CHN on =%d\n", __func__, ver); if (rc < 0) { tsp_debug_info(true, info->dev, "%s, read fail,%d\n", __func__, rc); } else if (ver == 0) { fts_enable_custom_library(info); info->fts_command(info, FTS_CMD_SAVE_FWCONFIG); msleep(300); info->fts_systemreset(info); info->fts_wait_for_ready(info); } } #endif void fts_fw_init(struct fts_ts_info *info) { /* fts_enable_custom_library : enable String library when use BlackUI/QuickApp/QuickCAM.. etc.. * after all Firmware config sending, send SAVE command. */ #ifdef FTS_SUPPORT_STRINGLIB fts_enable_custom_library(info); #endif // info->fts_command(info, SLEEPOUT); // msleep(50); if (info->stm_ver != STM_VER7) { info->fts_command(info, SLEEPOUT); msleep(50); if (info->digital_rev == FTS_DIGITAL_REV_2) { info->fts_command(info, FTS_CMD_TRIM_LOW_POWER_OSCILLATOR); msleep(300); info->fts_command(info, FTS_CMD_SAVE_CX_TUNING); msleep(230); fts_fw_wait_for_event(info, STATUS_EVENT_FLASH_WRITE_CXTUNE_VALUE); } } else { info->fts_command(info, FTS_CMD_TRIM_LOW_POWER_OSCILLATOR); msleep(200); } //TEST fts_execute_autotune(info); //TEST if (info->stm_ver != STM_VER7) { info->fts_command(info, SLEEPOUT); msleep(50); } info->fts_command(info, SENSEON); #ifdef FTS_SUPPORT_WATER_MODE fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); #else if (info->stm_ver == STM_VER7) { fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE_D3); } else { fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE); } #endif #ifdef FTS_SUPPORT_TOUCH_KEY if (info->dt_data->support_mskey) info->fts_command(info, FTS_CMD_KEY_SENSE_ON); #endif if (info->stm_ver == STM_VER7) { fts_interrupt_set(info, INT_ENABLE); msleep(20); } } const int fts_fw_updater(struct fts_ts_info *info, unsigned char *fw_data) { const struct fts64_header *header; int retval; int retry = 0; unsigned short fw_main_version; if (!fw_data) { tsp_debug_err(true, info->dev, "%s: Firmware data is NULL\n", __func__); return -ENODEV; } header = (struct fts64_header *)fw_data; fw_main_version = (header->released_ver[0] << 8) + (header->released_ver[1]); tsp_debug_info(true, info->dev, "Starting firmware update : 0x%04X\n", fw_main_version); while (1) { #ifdef FTS_SUPPORT_PARTIAL_DOWNLOAD info->o_afe_ver = info->afe_ver; #endif if (info->stm_ver == STM_VER7) retval = fts_fw_burn_stm7(info, fw_data); else retval = fts_fw_burn(info, fw_data); if (retval >= 0) { info->fts_wait_for_ready(info); info->fts_get_version_info(info); #ifdef FTS_SUPPORT_NOISE_PARAM info->fts_get_noise_param_address(info); #endif if (fw_main_version == info->fw_main_version_of_ic) { tsp_debug_info(true, info->dev, "%s: Success Firmware update\n", __func__); info->fts_systemreset(info); info->fts_delay(10); info->fts_wait_for_ready(info); fts_fw_init(info); retval = 0; break; } } if (retry++ > 2) { tsp_debug_err(true, info->dev, "%s: Fail Firmware update\n", __func__); retval = -1; break; } } /* set_tsp_test_result using backup data */ if (info->stm_ver == STM_VER7) { struct fts_ts_test_result result; retry = 0; do { result.data[0] = info->test_result.data[0]; fts_set_tsp_test_result(info); fts_get_tsp_test_result(info); retry++; } while ((result.data[0] != info->test_result.data[0]) && (retry < 5)); if (retry >= 5) { tsp_debug_err(true, info->dev, "%s: failed to set_tsp_test_result\n", __func__); } } return retval; } EXPORT_SYMBOL(fts_fw_updater); static bool fts_check_firmware_data(struct fts_ts_info *info, unsigned char *fw_data) { int config_id, num_rx, num_tx; config_id = fw_data[CONFIG_OFFSET_BIN_D3]; num_rx = fw_data[RX_OFFSET_BIN_D2]; num_tx = fw_data[TX_OFFSET_BIN_D2]; tsp_debug_info(true, info->dev, "%s: BIN:[%d] %d, %d // IC: %d, %d\n", __func__, config_id, num_rx, num_tx, info->SenseChannelLength, info->ForceChannelLength); return false; } int fts_fw_update_on_probe(struct fts_ts_info *info) { int retval; const struct firmware *fw_entry = NULL; unsigned char *fw_data = NULL; char fw_path[FTS_MAX_FW_PATH]; const struct fts64_header *header; unsigned char SYS_STAT[2]; #ifdef FTS_SUPPORT_STRINGLIB fts_check_custom_library(info); #endif if (info->digital_rev == FTS_DIGITAL_REV_3) { info->firmware_name = info->dt_data->firmware_name; } else { info->firmware_name = FTS_FIRMWARE_NAME_NULL; } snprintf(fw_path, FTS_MAX_FW_PATH, "%s", info->firmware_name); tsp_debug_info(true, info->dev, "%s: Load firmware : %s, Digital_rev : %d\n", __func__, fw_path, info->digital_rev); if (!info->firmware_name) { tsp_debug_info(true, info->dev, "%s: firmawer name is NULL, return\n", __func__); return 0; } retval = request_firmware(&fw_entry, fw_path, info->dev); if (retval) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available\n", __func__, fw_path); goto update_on_probe_done; } if ((info->digital_rev == FTS_DIGITAL_REV_1) && fw_entry->size != (FW_IMAGE_SIZE_D1 + sizeof(struct fts64_header))) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available for FTS D1\n", __func__, fw_path); goto update_on_probe_done; } if ((info->digital_rev == FTS_DIGITAL_REV_2) && fw_entry->size != (FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header))) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available for FTS D2\n", __func__, fw_path); goto update_on_probe_done; } fw_data = (unsigned char *)fw_entry->data; header = (struct fts64_header *)fw_data; info->fw_version_of_bin = (fw_data[5] << 8) + fw_data[4]; info->fw_main_version_of_bin = (header->released_ver[0] << 8) + (header->released_ver[1]); if (info->digital_rev == FTS_DIGITAL_REV_1) info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D1] << 8) + fw_data[CONFIG_OFFSET_BIN_D1 - 1]; else if (info->digital_rev == FTS_DIGITAL_REV_2) info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D2] << 8) + fw_data[CONFIG_OFFSET_BIN_D2 - 1]; else info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D3] << 8) + fw_data[CONFIG_OFFSET_BIN_D3 - 1]; tsp_debug_info(true, info->dev, "Bin Firmware Version : 0x%04X, Bin Config Version : 0x%04X, Bin Main Version : 0x%04X\n", info->fw_version_of_bin, info->config_version_of_bin, info->fw_main_version_of_bin); fts_check_firmware_data(info, fw_data); /* * skip firmware update @ bringup flag is enabled in device tree. */ if (info->dt_data->bringup) { tsp_debug_err(true, info->dev, "%s: not update\n", __func__); return 0; } /* check core + config + main */ if ((info->fw_main_version_of_ic < info->fw_main_version_of_bin) || (info->config_version_of_ic < info->config_version_of_bin) || (info->fw_version_of_ic < info->fw_version_of_bin)) retval = fts_fw_updater(info, fw_data); else retval = FTS_NOT_ERROR; if (fts_get_system_status(info, &SYS_STAT[0], &SYS_STAT[1]) >= 0) if (SYS_STAT[0] != SYS_STAT[1]) { info->fts_systemreset(info); info->fts_delay(10); info->fts_wait_for_ready(info); fts_fw_init(info); } update_on_probe_done: if (fw_entry) release_firmware(fw_entry); /* if (retval < 0) { if (fts_get_system_status(info, &SYS_STAT[0], &SYS_STAT[1]) >= 0) { if (SYS_STAT[0] != SYS_STAT[1]) fts_fw_init(info); } } */ return retval; } EXPORT_SYMBOL(fts_fw_update_on_probe); static int fts_load_fw_from_kernel(struct fts_ts_info *info, const char *fw_path) { int retval; const struct firmware *fw_entry = NULL; unsigned char *fw_data = NULL; if (!fw_path) { tsp_debug_err(true, info->dev, "%s: Firmware name is not defined\n", __func__); return -EINVAL; } tsp_debug_info(true, info->dev, "%s: Load firmware : %s\n", __func__, fw_path); retval = request_firmware(&fw_entry, fw_path, info->dev); if (retval) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available\n", __func__, fw_path); goto load_kernel_done; } fw_data = (unsigned char *)fw_entry->data; if (info->irq) fts_irq_enable(info, false); else hrtimer_cancel(&info->timer); info->fts_systemreset(info); info->fts_wait_for_ready(info); retval = fts_fw_updater(info, fw_data); if (retval) tsp_debug_err(true, info->dev, "%s: failed update firmware\n", __func__); if (info->irq) fts_irq_enable(info, true); else hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); load_kernel_done: if (fw_entry) release_firmware(fw_entry); return retval; } static int fts_load_fw_from_ums(struct fts_ts_info *info) { struct file *fp; mm_segment_t old_fs; long fw_size, nread; int error = 0; old_fs = get_fs(); set_fs(KERNEL_DS); fp = filp_open(FTS_DEFAULT_UMS_FW, O_RDONLY, S_IRUSR); if (IS_ERR(fp)) { tsp_debug_err(true, info->dev, "%s: failed to open %s.\n", __func__, FTS_DEFAULT_UMS_FW); error = -ENOENT; goto open_err; } fw_size = fp->f_path.dentry->d_inode->i_size; if (0 < fw_size) { unsigned char *fw_data; const struct fts64_header *header; fw_data = kzalloc(fw_size, GFP_KERNEL); nread = vfs_read(fp, (char __user *)fw_data, fw_size, &fp->f_pos); tsp_debug_info(true, info->dev, "%s: start, file path %s, size %ld Bytes\n", __func__, FTS_DEFAULT_UMS_FW, fw_size); if (nread != fw_size) { tsp_debug_err(true, info->dev, "%s: failed to read firmware file, nread %ld Bytes\n", __func__, nread); error = -EIO; } else { header = (struct fts64_header *)fw_data; if (header->signature == FTS64FILE_SIGNATURE) { if (info->irq) fts_irq_enable(info, false); else hrtimer_cancel(&info->timer); info->fts_systemreset(info); info->fts_wait_for_ready(info); tsp_debug_info(true, info->dev, "[UMS] Firmware Version : 0x%04X, [UMS] Main Version : 0x%04X\n", (fw_data[5] << 8) + fw_data[4], (header->released_ver[0] << 8) + (header->released_ver[1])); error = fts_fw_updater(info, fw_data); if (info->irq) fts_irq_enable(info, true); else hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); } else { error = -1; tsp_debug_err(true, info->dev, "%s: File type is not match with FTS64 file. [%8x]\n", __func__, header->signature); } } if (error < 0) tsp_debug_err(true, info->dev, "%s: failed update firmware\n", __func__); kfree(fw_data); } filp_close(fp, NULL); open_err: set_fs(old_fs); return error; } static int fts_load_fw_from_ffu(struct fts_ts_info *info) { int retval; const struct firmware *fw_entry = NULL; unsigned char *fw_data = NULL; const char *fw_path = FTS_DEFAULT_FFU_FW; const struct fts64_header *header; if (!fw_path) { tsp_debug_err(true, info->dev, "%s: Firmware name is not defined\n", __func__); return -EINVAL; } tsp_debug_info(true, info->dev, "%s: Load firmware : %s\n", __func__, fw_path); retval = request_firmware(&fw_entry, fw_path, info->dev); if (retval) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available\n", __func__, fw_path); goto load_ffu_done; } if (info->digital_rev == FTS_DIGITAL_REV_2 && fw_entry->size!=(FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header))) { tsp_debug_err(true, info->dev, "%s: Firmware image %s not available for FTS D2\n", __func__, fw_path); goto load_ffu_done; } fw_data = (unsigned char *)fw_entry->data; header = (struct fts64_header *)fw_data; info->fw_version_of_bin = (fw_data[5] << 8)+fw_data[4]; info->fw_main_version_of_bin = (header->released_ver[0] << 8) + (header->released_ver[1]); if (info->digital_rev == FTS_DIGITAL_REV_1) info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D1] << 8) + fw_data[CONFIG_OFFSET_BIN_D1 - 1]; else if (info->digital_rev == FTS_DIGITAL_REV_2) info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D2] << 8) + fw_data[CONFIG_OFFSET_BIN_D2 - 1]; else info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D3] << 8) + fw_data[CONFIG_OFFSET_BIN_D3 - 1]; tsp_debug_info(true, info->dev, "FFU Firmware Version : 0x%04X " "FFU Config Version : 0x%04X " "FFU Main Version : 0x%04X\n", info->fw_version_of_bin, info->config_version_of_bin, info->fw_main_version_of_bin); /* TODO : if you need to check firmware version between IC and Binary, * add it this position. */ if (info->irq) fts_irq_enable(info, false); else hrtimer_cancel(&info->timer); info->fts_systemreset(info); info->fts_wait_for_ready(info); retval = fts_fw_updater(info, fw_data); if (retval) tsp_debug_err(true, info->dev, "%s: failed update firmware\n", __func__); if (info->irq) fts_irq_enable(info, true); else hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); load_ffu_done: if (fw_entry) release_firmware(fw_entry); return retval; } int fts_fw_update_on_hidden_menu(struct fts_ts_info *info, int update_type) { int retval = 0; /* Factory cmd for firmware update * argument represent what is source of firmware like below. * * 0 : [BUILT_IN] Getting firmware which is for user. * 1 : [UMS] Getting firmware from sd card. * 2 : none * 3 : [FFU] Getting firmware from air. */ switch (update_type) { case BUILT_IN: retval = fts_load_fw_from_kernel(info, info->firmware_name); break; case UMS: retval = fts_load_fw_from_ums(info); break; case FFU: retval = fts_load_fw_from_ffu(info); break; default: tsp_debug_err(true, info->dev, "%s: Not support command[%d]\n", __func__, update_type); break; } return retval; } EXPORT_SYMBOL(fts_fw_update_on_hidden_menu);