1175 lines
30 KiB
C
1175 lines
30 KiB
C
|
#include <linux/kernel.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/input.h>
|
||
|
#include <linux/firmware.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <linux/hrtimer.h>
|
||
|
#include <linux/interrupt.h>
|
||
|
#include <linux/gpio.h>
|
||
|
|
||
|
#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);
|