1452 lines
40 KiB
C
Executable file
1452 lines
40 KiB
C
Executable file
/*
|
|
*
|
|
* FocalTech fts TouchScreen driver.
|
|
*
|
|
* Copyright (c) 2012-2020, Focaltech Ltd. All rights reserved.
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* File Name: focaltech_flash.c
|
|
*
|
|
* Author: Focaltech Driver Team
|
|
*
|
|
* Created: 2017-12-06
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Reference:
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* 1.Included header files
|
|
*****************************************************************************/
|
|
#include "focaltech_core.h"
|
|
#include "focaltech_flash.h"
|
|
//drv add hardware info -20240717-start
|
|
#if IS_ENABLED(CONFIG_PRIZE_HARDWARE_INFO)
|
|
#include "../../../misc/mediatek/prize/hardware_info/hardware_info.h"
|
|
extern struct hardware_info current_tp_info;
|
|
#endif
|
|
//drv add hardware info -20240717-end
|
|
/*****************************************************************************
|
|
* Private constant and macro definitions using #define
|
|
*****************************************************************************/
|
|
#define FTS_FW_REQUEST_SUPPORT 1
|
|
/* Example: focaltech_ts_fw_tianma.bin */
|
|
#define FTS_FW_NAME_PREX_WITH_REQUEST "focaltech_ts_fw_"
|
|
#define FTS_READ_BOOT_ID_TIMEOUT 3
|
|
#define FTS_FLASH_PACKET_LENGTH_SPI_LOW (4 * 1024 - 4)
|
|
#define FTS_FLASH_PACKET_LENGTH_SPI (32 * 1024 - 16)
|
|
|
|
/*****************************************************************************
|
|
* Private enumerations, structures and unions using typedef
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Global variable or extern global variabls/functions
|
|
*****************************************************************************/
|
|
u8 fw_file[] = {
|
|
#include FTS_UPGRADE_FW_FILE
|
|
};
|
|
|
|
u8 fw_file2[] = {
|
|
#include FTS_UPGRADE_FW2_FILE
|
|
};
|
|
|
|
u8 fw_file3[] = {
|
|
#include FTS_UPGRADE_FW3_FILE
|
|
};
|
|
|
|
struct upgrade_module module_list[] = {
|
|
{FTS_MODULE_ID, FTS_MODULE_NAME, fw_file, sizeof(fw_file)},
|
|
{FTS_MODULE2_ID, FTS_MODULE2_NAME, fw_file2, sizeof(fw_file2)},
|
|
{FTS_MODULE3_ID, FTS_MODULE3_NAME, fw_file3, sizeof(fw_file3)},
|
|
};
|
|
|
|
struct upgrade_setting_nf upgrade_setting_list[] = {
|
|
{0x87, 0x19, 0, (64 * 1024), (128 * 1024), 0x00, 0x02, 8, 1, 1, 1, 0, 0},
|
|
{0x86, 0x22, 0, (64 * 1024), (128 * 1024), 0x00, 0x02, 8, 1, 1, 0, 0, 0},
|
|
{0x87, 0x56, 0, (88 * 1024), 32766, 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x80, 0x09, 0, (88 * 1024), 32766, 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x86, 0x32, 0, (64 * 1024), (128 * 1024), 0xA5, 0x01, 12, 0, 1, 0, 0, 0},
|
|
{0x86, 0x42, 0, (64 * 1024), (128 * 1024), 0xA5, 0x01, 12, 0, 1, 0, 0, 0},
|
|
{0x87, 0x20, 0, (88 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x87, 0x22, 0, (88 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x82, 0x01, 0, (96 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 0, 0},
|
|
{0xF0, 0xC6, 0, (84 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x56, 0x62, 0, (128 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 4, 0, 0, 5},
|
|
{0x82, 0x05, 0, (120 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 0, 0},
|
|
{0x80, 0x57, 0, (84 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x80, 0xC7, 0, (84 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x23, 0x89, 0, (88 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x87, 0x25, 0, (88 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 1, 0},
|
|
{0x82, 0x06, 0, (128 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 0, 0},
|
|
{0x82, 0xC5, 0, (128 * 1024), (128 * 1024), 0xA5, 0x01, 8, 0, 2, 0, 0, 0},
|
|
};
|
|
|
|
struct fts_upgrade *fwupgrade;
|
|
|
|
static int fts_check_bootid(void)
|
|
{
|
|
int ret = 0;
|
|
u8 cmd = 0;
|
|
u8 id[2] = { 0 };
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
struct ft_chip_t *chip_id;
|
|
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
chip_id = &upg->ts_data->ic_info.ids;
|
|
|
|
cmd = FTS_CMD_READ_ID;
|
|
ret = fts_read(&cmd, 1, id, 2);
|
|
if (ret < 0) {
|
|
FTS_ERROR("read boot id(0x%02x 0x%02x) fail", id[0], id[1]);
|
|
return ret;
|
|
}
|
|
|
|
FTS_INFO("read boot id:0x%02x 0x%02x", id[0], id[1]);
|
|
if ((chip_id->rom_idh == id[0]) && (chip_id->rom_idl == id[1])) {
|
|
return 0;
|
|
}
|
|
|
|
return -EIO;
|
|
}
|
|
|
|
static int fts_enter_into_boot(void)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
u8 cmd[2] = { 0 };
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
FTS_INFO("enter into boot environment");
|
|
for (i = 0; i < FTS_UPGRADE_LOOP; i++) {
|
|
/* hardware tp reset to boot */
|
|
fts_reset_proc(upg->ts_data, true, 0);
|
|
mdelay(upg->setting_nf->delay_init + i * 2);
|
|
/* enter into boot & check boot id*/
|
|
for (j = 0; j < FTS_READ_BOOT_ID_TIMEOUT; j++) {
|
|
cmd[0] = FTS_CMD_START1;
|
|
ret = fts_write(cmd, 1);
|
|
if (ret >= 0) {
|
|
fts_msleep(upg->setting_nf->delay_init);
|
|
ret = fts_check_bootid();
|
|
if (0 == ret) {
|
|
FTS_INFO("boot id check pass, retry=%d", i);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -EIO;
|
|
}
|
|
|
|
static bool fts_check_fast_download(void)
|
|
{
|
|
int ret = 0;
|
|
u8 cmd[6] = {0xF2, 0x00, 0x78, 0x0A, 0x00, 0x02};
|
|
u8 value = 0;
|
|
u8 value2[2] = { 0 };
|
|
|
|
ret = fts_read_reg(0xdb, &value);
|
|
if (ret < 0) {
|
|
FTS_ERROR("read 0xdb fail");
|
|
goto read_err;
|
|
}
|
|
|
|
ret = fts_read(cmd, 6, value2, 2);
|
|
if (ret < 0) {
|
|
FTS_ERROR("read f2 fail");
|
|
goto read_err;
|
|
}
|
|
|
|
FTS_INFO("0xdb = 0x%x, 0xF2 = 0x%x", value, value2[0]);
|
|
if ((value >= 0x18) && (value2[0] == 0x55)) {
|
|
FTS_INFO("IC support fast-download");
|
|
return true;
|
|
}
|
|
|
|
read_err:
|
|
FTS_INFO("IC not support fast-download");
|
|
return false;
|
|
}
|
|
|
|
static int fts_dpram_write_pe(u32 saddr, const u8 *buf, u32 len, bool wpram)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
u8 *cmd = NULL;
|
|
u32 addr = 0;
|
|
u32 offset = 0;
|
|
u32 remainder = 0;
|
|
u32 packet_number = 0;
|
|
u32 packet_len = 0;
|
|
u32 packet_size = FTS_FLASH_PACKET_LENGTH_SPI;
|
|
bool fd_support = true;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("dpram write");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!buf) {
|
|
FTS_ERROR("fw buf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((len < FTS_MIN_LEN) || (len > upg->setting_nf->app2_offset)) {
|
|
FTS_ERROR("fw length(%d) fail", len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->setting_nf->fd_check) {
|
|
fd_support = fts_check_fast_download();
|
|
if (!fd_support)
|
|
packet_size = FTS_FLASH_PACKET_LENGTH_SPI_LOW;
|
|
}
|
|
|
|
cmd = vmalloc(packet_size + FTS_CMD_WRITE_LEN + 1);
|
|
if (NULL == cmd) {
|
|
FTS_ERROR("malloc memory for pram write buffer fail");
|
|
return -ENOMEM;
|
|
}
|
|
memset(cmd, 0, packet_size + FTS_CMD_WRITE_LEN + 1);
|
|
|
|
packet_number = len / packet_size;
|
|
remainder = len % packet_size;
|
|
if (remainder > 0)
|
|
packet_number++;
|
|
packet_len = packet_size;
|
|
FTS_INFO("write data, num:%d remainder:%d", packet_number, remainder);
|
|
|
|
cmd[0] = FTS_ROMBOOT_CMD_WRITE;
|
|
for (i = 0; i < packet_number; i++) {
|
|
offset = i * packet_size;
|
|
addr = saddr + offset;
|
|
cmd[1] = BYTE_OFF_16(addr);
|
|
cmd[2] = BYTE_OFF_8(addr);
|
|
cmd[3] = BYTE_OFF_0(addr);
|
|
|
|
/* last packet */
|
|
if ((i == (packet_number - 1)) && remainder)
|
|
packet_len = remainder;
|
|
cmd[4] = BYTE_OFF_8(packet_len);
|
|
cmd[5] = BYTE_OFF_0(packet_len);
|
|
|
|
for (j = 0; j < packet_len; j++) {
|
|
cmd[FTS_CMD_WRITE_LEN + j] = buf[offset + j];
|
|
}
|
|
|
|
ret = fts_write(&cmd[0], FTS_CMD_WRITE_LEN + packet_len);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write fw to pram(%d) fail", i);
|
|
goto write_pram_err;
|
|
}
|
|
|
|
if (!fd_support)
|
|
fts_msleep(3);
|
|
}
|
|
|
|
write_pram_err:
|
|
if (cmd) {
|
|
vfree(cmd);
|
|
cmd = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int fts_dpram_write(u32 saddr, const u8 *buf, u32 len, bool wpram)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
int j = 0;
|
|
u8 *cmd = NULL;
|
|
u32 addr = 0;
|
|
u32 baseaddr = wpram ? FTS_PRAM_SADDR : FTS_DRAM_SADDR;
|
|
u32 offset = 0;
|
|
u32 remainder = 0;
|
|
u32 packet_number = 0;
|
|
u32 packet_len = 0;
|
|
u32 packet_size = FTS_FLASH_PACKET_LENGTH_SPI;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("dpram write");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!buf) {
|
|
FTS_ERROR("fw buf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((len < FTS_MIN_LEN) || (len > upg->setting_nf->app2_offset)) {
|
|
FTS_ERROR("fw length(%d) fail", len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
cmd = vmalloc(packet_size + FTS_CMD_WRITE_LEN + 1);
|
|
if (NULL == cmd) {
|
|
FTS_ERROR("malloc memory for pram write buffer fail");
|
|
return -ENOMEM;
|
|
}
|
|
memset(cmd, 0, packet_size + FTS_CMD_WRITE_LEN + 1);
|
|
|
|
packet_number = len / packet_size;
|
|
remainder = len % packet_size;
|
|
if (remainder > 0)
|
|
packet_number++;
|
|
packet_len = packet_size;
|
|
FTS_INFO("write data, num:%d remainder:%d", packet_number, remainder);
|
|
|
|
for (i = 0; i < packet_number; i++) {
|
|
offset = i * packet_size;
|
|
addr = saddr + offset + baseaddr;
|
|
/* last packet */
|
|
if ((i == (packet_number - 1)) && remainder)
|
|
packet_len = remainder;
|
|
|
|
/* set pram address */
|
|
cmd[0] = FTS_ROMBOOT_CMD_SET_PRAM_ADDR;
|
|
cmd[1] = BYTE_OFF_16(addr);
|
|
cmd[2] = BYTE_OFF_8(addr);
|
|
cmd[3] = BYTE_OFF_0(addr);
|
|
ret = fts_write(&cmd[0], FTS_ROMBOOT_CMD_SET_PRAM_ADDR_LEN);
|
|
if (ret < 0) {
|
|
FTS_ERROR("set pram(%d) addr(%d) fail", i, addr);
|
|
goto write_pram_err;
|
|
}
|
|
|
|
/* write pram data */
|
|
cmd[0] = FTS_ROMBOOT_CMD_WRITE;
|
|
for (j = 0; j < packet_len; j++) {
|
|
cmd[1 + j] = buf[offset + j];
|
|
}
|
|
ret = fts_write(&cmd[0], 1 + packet_len);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write fw to pram(%d) fail", i);
|
|
goto write_pram_err;
|
|
}
|
|
}
|
|
|
|
write_pram_err:
|
|
if (cmd) {
|
|
vfree(cmd);
|
|
cmd = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int fts_ecc_cal_tp(u32 ecc_saddr, u32 ecc_len, u16 *ecc_value)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
u8 cmd[FTS_ROMBOOT_CMD_ECC_NEW_LEN] = { 0 };
|
|
u8 value[2] = { 0 };
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("ecc calc in tp");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
cmd[0] = FTS_ROMBOOT_CMD_ECC;
|
|
cmd[1] = BYTE_OFF_16(ecc_saddr);
|
|
cmd[2] = BYTE_OFF_8(ecc_saddr);
|
|
cmd[3] = BYTE_OFF_0(ecc_saddr);
|
|
cmd[4] = BYTE_OFF_16(ecc_len);
|
|
cmd[5] = BYTE_OFF_8(ecc_len);
|
|
cmd[6] = BYTE_OFF_0(ecc_len);
|
|
|
|
/* make boot to calculate ecc in pram */
|
|
ret = fts_write(cmd, FTS_ROMBOOT_CMD_ECC_NEW_LEN);
|
|
if (ret < 0) {
|
|
FTS_ERROR("ecc calc cmd fail");
|
|
return ret;
|
|
}
|
|
fts_msleep(2);
|
|
|
|
/* wait boot calculate ecc finish */
|
|
if (upg->setting_nf->ecc_delay) {
|
|
fts_msleep(upg->setting_nf->ecc_delay);
|
|
} else {
|
|
cmd[0] = FTS_ROMBOOT_CMD_ECC_FINISH;
|
|
for (i = 0; i < FTS_ECC_FINISH_TIMEOUT; i++) {
|
|
ret = fts_read(cmd, 1, value, 1);
|
|
if (ret < 0) {
|
|
FTS_ERROR("ecc finish cmd fail");
|
|
return ret;
|
|
}
|
|
if (upg->setting_nf->eccok_val == value[0])
|
|
break;
|
|
fts_msleep(1);
|
|
}
|
|
if (i >= FTS_ECC_FINISH_TIMEOUT) {
|
|
FTS_ERROR("wait ecc finish timeout,ecc_finish=%x", value[0]);
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
/* get ecc value calculate in boot */
|
|
cmd[0] = FTS_ROMBOOT_CMD_ECC_READ;
|
|
ret = fts_read(cmd, 1, value, 2);
|
|
if (ret < 0) {
|
|
FTS_ERROR("ecc read cmd fail");
|
|
return ret;
|
|
}
|
|
|
|
*ecc_value = ((u16)(value[0] << 8) + value[1]) & 0x0000FFFF;
|
|
return 0;
|
|
}
|
|
|
|
static int fts_ecc_cal_host(const u8 *data, u32 data_len, u16 *ecc_value)
|
|
{
|
|
u16 ecc = 0;
|
|
u32 i = 0;
|
|
u32 j = 0;
|
|
u16 al2_fcs_coef = AL2_FCS_COEF;
|
|
|
|
for (i = 0; i < data_len; i += 2 ) {
|
|
ecc ^= ((data[i] << 8) | (data[i + 1]));
|
|
for (j = 0; j < 16; j ++) {
|
|
if (ecc & 0x01)
|
|
ecc = (u16)((ecc >> 1) ^ al2_fcs_coef);
|
|
else
|
|
ecc >>= 1;
|
|
}
|
|
}
|
|
|
|
*ecc_value = ecc & 0x0000FFFF;
|
|
return 0;
|
|
}
|
|
|
|
static int fts_ecc_check(const u8 *buf, u32 len, u32 ecc_saddr)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
u16 ecc_in_host = 0;
|
|
u16 ecc_in_tp = 0;
|
|
int packet_length = 0;
|
|
int packet_number = 0;
|
|
int packet_remainder = 0;
|
|
int offset = 0;
|
|
u32 packet_size = FTS_MAX_LEN_FILE;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("ecc check");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->setting_nf->ecclen_max) {
|
|
packet_size = upg->setting_nf->ecclen_max;
|
|
}
|
|
|
|
packet_number = len / packet_size;
|
|
packet_remainder = len % packet_size;
|
|
if (packet_remainder)
|
|
packet_number++;
|
|
packet_length = packet_size;
|
|
|
|
for (i = 0; i < packet_number; i++) {
|
|
/* last packet */
|
|
if ((i == (packet_number - 1)) && packet_remainder)
|
|
packet_length = packet_remainder;
|
|
|
|
ret = fts_ecc_cal_host(buf + offset, packet_length, &ecc_in_host);
|
|
if (ret < 0) {
|
|
FTS_ERROR("ecc in host calc fail");
|
|
return ret;
|
|
}
|
|
|
|
ret = fts_ecc_cal_tp(ecc_saddr + offset, packet_length, &ecc_in_tp);
|
|
if (ret < 0) {
|
|
FTS_ERROR("ecc in tp calc fail");
|
|
return ret;
|
|
}
|
|
|
|
FTS_DEBUG("ecc in tp:%04x,host:%04x,i:%d", ecc_in_tp, ecc_in_host, i);
|
|
if (ecc_in_tp != ecc_in_host) {
|
|
FTS_ERROR("ecc_in_tp(%x) != ecc_in_host(%x), ecc check fail",
|
|
ecc_in_tp, ecc_in_host);
|
|
return -EIO;
|
|
}
|
|
|
|
offset += packet_length;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fts_pram_write_ecc(const u8 *buf, u32 len)
|
|
{
|
|
int ret = 0;
|
|
u32 pram_app_size = 0;
|
|
u16 code_len = 0;
|
|
u16 code_len_n = 0;
|
|
u32 pram_start_addr = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("begin to write pram app(bin len:%d)", len);
|
|
if (!upg || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* get pram app length */
|
|
code_len = ((u16)buf[FTS_APP_INFO_OFFSET + 0] << 8)
|
|
+ buf[FTS_APP_INFO_OFFSET + 1];
|
|
code_len_n = ((u16)buf[FTS_APP_INFO_OFFSET + 2] << 8)
|
|
+ buf[FTS_APP_INFO_OFFSET + 3];
|
|
if ((code_len + code_len_n) != 0xFFFF) {
|
|
FTS_ERROR("pram code len(%x %x) fail", code_len, code_len_n);
|
|
return -EINVAL;
|
|
}
|
|
|
|
pram_app_size = ((u32)code_len) * upg->setting_nf->length_coefficient;
|
|
FTS_INFO("pram app length in fact:%d", pram_app_size);
|
|
|
|
/* write pram */
|
|
if (upg->setting_nf->spi_pe)
|
|
ret = fts_dpram_write_pe(pram_start_addr, buf, pram_app_size, true);
|
|
else
|
|
ret = fts_dpram_write(pram_start_addr, buf, pram_app_size, true);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write pram fail");
|
|
return ret;
|
|
}
|
|
|
|
/* check ecc */
|
|
ret = fts_ecc_check(buf, pram_app_size, pram_start_addr);
|
|
if (ret < 0) {
|
|
FTS_ERROR("pram ecc check fail");
|
|
return ret;
|
|
}
|
|
|
|
FTS_INFO("pram app write successfully");
|
|
return 0;
|
|
}
|
|
|
|
static int fts_dram_write_ecc(const u8 *buf, u32 len)
|
|
{
|
|
int ret = 0;
|
|
u32 dram_size = 0;
|
|
u32 pram_app_size = 0;
|
|
u32 dram_start_addr = 0;
|
|
u16 const_len = 0;
|
|
u16 const_len_n = 0;
|
|
const u8 *dram_buf = NULL;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("begin to write dram data(bin len:%d)", len);
|
|
if (!upg || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* get dram data length */
|
|
const_len = ((u16)buf[FTS_APP_INFO_OFFSET + 0x8] << 8)
|
|
+ buf[FTS_APP_INFO_OFFSET + 0x9];
|
|
const_len_n = ((u16)buf[FTS_APP_INFO_OFFSET + 0x0A] << 8)
|
|
+ buf[FTS_APP_INFO_OFFSET + 0x0B];
|
|
if (((const_len + const_len_n) != 0xFFFF) || (const_len == 0)) {
|
|
FTS_INFO("no support dram,const len(%x %x)", const_len, const_len_n);
|
|
return 0;
|
|
}
|
|
|
|
dram_size = ((u32)const_len) * upg->setting_nf->length_coefficient;
|
|
pram_app_size = ((u32)(((u16)buf[FTS_APP_INFO_OFFSET + 0] << 8)
|
|
+ buf[FTS_APP_INFO_OFFSET + 1]));
|
|
pram_app_size = pram_app_size * upg->setting_nf->length_coefficient;
|
|
|
|
dram_buf = buf + pram_app_size;
|
|
FTS_INFO("dram buf length in fact:%d,offset:%d", dram_size, pram_app_size);
|
|
/* write pram */
|
|
ret = fts_dpram_write(dram_start_addr, dram_buf, dram_size, false);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write dram fail");
|
|
return ret;
|
|
}
|
|
|
|
/* check ecc */
|
|
ret = fts_ecc_check(dram_buf, dram_size, dram_start_addr);
|
|
if (ret < 0) {
|
|
FTS_ERROR("dram ecc check fail");
|
|
return ret;
|
|
}
|
|
|
|
FTS_INFO("dram data write successfully");
|
|
return 0;
|
|
}
|
|
|
|
static int fts_pram_start(void)
|
|
{
|
|
int ret = 0;
|
|
u8 cmd = FTS_ROMBOOT_CMD_START_APP;
|
|
|
|
FTS_INFO("remap to start pram");
|
|
ret = fts_write(&cmd, 1);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write start pram cmd fail");
|
|
return ret;
|
|
}
|
|
|
|
fts_msleep(10);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* description: download fw to IC and run
|
|
*
|
|
* param - buf: const, fw data buffer
|
|
* len: length of fw
|
|
*
|
|
* return 0 if success, otherwise return error code
|
|
*/
|
|
static int fts_fw_write_start(const u8 *buf, u32 len, bool need_reset)
|
|
{
|
|
int ret = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("begin to write and start fw(bin len:%d)", len);
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
upg->ts_data->fw_is_running = false;
|
|
|
|
if (need_reset) {
|
|
/* enter into boot environment */
|
|
ret = fts_enter_into_boot();
|
|
if (ret < 0) {
|
|
FTS_ERROR("enter into boot environment fail");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* write pram */
|
|
ret = fts_pram_write_ecc(buf, len);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write pram fail");
|
|
return ret;
|
|
}
|
|
|
|
if (upg->setting_nf->drwr_support) {
|
|
/* write dram */
|
|
ret = fts_dram_write_ecc(buf, len);
|
|
if (ret < 0) {
|
|
FTS_ERROR("write dram fail");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* remap pram and run fw */
|
|
ret = fts_pram_start();
|
|
if (ret < 0) {
|
|
FTS_ERROR("pram start fail");
|
|
return ret;
|
|
}
|
|
|
|
upg->ts_data->fw_is_running = true;
|
|
FTS_INFO("fw download successfully");
|
|
return 0;
|
|
}
|
|
|
|
static int fts_fw_download(const u8 *buf, u32 len, bool need_reset)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
int irq_need_recovery = false;
|
|
int esd_need_recovery = false;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("fw upgrade download function");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!buf || (len < FTS_MIN_LEN)) {
|
|
FTS_ERROR("fw/len(%d) is invalid", len);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return -EINVAL;
|
|
}
|
|
|
|
upg->ts_data->fw_loading = 1;
|
|
if (!upg->ts_data->irq_disabled) {
|
|
fts_irq_disable();
|
|
irq_need_recovery = true;
|
|
}
|
|
if (fts_esdcheck_is_running(upg->ts_data)) {
|
|
fts_esdcheck_switch(upg->ts_data, DISABLE);
|
|
esd_need_recovery = true;
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
FTS_INFO("fw download times:%d", i + 1);
|
|
ret = fts_fw_write_start(buf, len, need_reset);
|
|
if (0 == ret)
|
|
break;
|
|
}
|
|
if (i >= 3) {
|
|
FTS_ERROR("fw download fail");
|
|
ret = -EIO;
|
|
goto err_fw_download;
|
|
}
|
|
|
|
if (esd_need_recovery) fts_esdcheck_switch(upg->ts_data, ENABLE);
|
|
ret = 0;
|
|
err_fw_download:
|
|
if (irq_need_recovery) fts_irq_enable();
|
|
upg->ts_data->fw_loading = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int fts_read_file_default(char *file_name, u8 **file_buf)
|
|
{
|
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0))
|
|
int ret = 0;
|
|
char file_path[FILE_NAME_LENGTH] = { 0 };
|
|
struct file *filp = NULL;
|
|
struct inode *inode;
|
|
mm_segment_t old_fs;
|
|
loff_t pos;
|
|
loff_t file_len = 0;
|
|
|
|
if ((NULL == file_name) || (NULL == file_buf)) {
|
|
FTS_ERROR("filename/filebuf is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
snprintf(file_path, FILE_NAME_LENGTH, "%s%s", FTS_FW_BIN_FILEPATH, file_name);
|
|
filp = filp_open(file_path, O_RDONLY, 0);
|
|
if (IS_ERR(filp)) {
|
|
FTS_ERROR("open %s file fail", file_path);
|
|
return -ENOENT;
|
|
}
|
|
|
|
#if 1
|
|
inode = filp->f_inode;
|
|
#else
|
|
/* reserved for linux earlier verion */
|
|
inode = filp->f_dentry->d_inode;
|
|
#endif
|
|
|
|
file_len = inode->i_size;
|
|
*file_buf = (u8 *)vmalloc(file_len);
|
|
if (NULL == *file_buf) {
|
|
FTS_ERROR("file buf malloc fail");
|
|
filp_close(filp, NULL);
|
|
return -ENOMEM;
|
|
}
|
|
old_fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
pos = 0;
|
|
ret = vfs_read(filp, *file_buf, file_len , &pos);
|
|
if (ret < 0)
|
|
FTS_ERROR("read file fail");
|
|
FTS_INFO("file len:%d read len:%d pos:%d", (u32)file_len, ret, (u32)pos);
|
|
filp_close(filp, NULL);
|
|
set_fs(old_fs);
|
|
return ret;
|
|
#else
|
|
FTS_INFO("not support vfs_read to get fw file");
|
|
return -EINVAL;
|
|
#endif
|
|
}
|
|
|
|
static int fts_read_file_request_firmware(char *file_name, u8 **file_buf)
|
|
{
|
|
#if FTS_FW_REQUEST_SUPPORT
|
|
int ret = 0;
|
|
const struct firmware *fw = NULL;
|
|
char fwname[FILE_NAME_LENGTH] = { 0 };
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
snprintf(fwname, FILE_NAME_LENGTH, "%s", file_name);
|
|
ret = request_firmware(&fw, fwname, upg->ts_data->dev);
|
|
if (0 == ret) {
|
|
FTS_INFO("firmware(%s) request successfully", fwname);
|
|
*file_buf = vmalloc(fw->size);
|
|
if (NULL == *file_buf) {
|
|
FTS_ERROR("fw buffer vmalloc fail");
|
|
ret = -ENOMEM;
|
|
} else {
|
|
memcpy(*file_buf, fw->data, fw->size);
|
|
ret = fw->size;
|
|
}
|
|
} else {
|
|
FTS_INFO("firmware(%s) request fail,ret=%d", fwname, ret);
|
|
ret = -EIO;
|
|
}
|
|
|
|
if (fw != NULL) {
|
|
release_firmware(fw);
|
|
fw = NULL;
|
|
}
|
|
|
|
return ret;
|
|
#else
|
|
FTS_INFO("not support request_firmware to get fw file");
|
|
return -EINVAL;
|
|
#endif
|
|
}
|
|
|
|
static int fts_read_file(char *file_name, u8 **file_buf)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = fts_read_file_request_firmware(file_name, file_buf);
|
|
if (ret < 0) {
|
|
ret = fts_read_file_default(file_name, file_buf);
|
|
if (ret < 0) {
|
|
FTS_INFO("get fw file(default) abnormal");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int fts_upgrade_bin(char *fw_name, bool force)
|
|
{
|
|
int ret = 0;
|
|
u32 fw_file_len = 0;
|
|
u8 *fw_file_buf = NULL;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("start upgrade with fw bin");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = fts_read_file(fw_name, &fw_file_buf);
|
|
if ((ret < 0) || (ret < FTS_MIN_LEN)) {
|
|
FTS_ERROR("read fw bin file(%s) fail, len:%d", fw_name, ret);
|
|
goto err_bin;
|
|
}
|
|
|
|
fw_file_len = ret;
|
|
FTS_INFO("fw bin file len:%d", fw_file_len);
|
|
ret = fts_fw_download(fw_file_buf, fw_file_len, true);
|
|
if (ret < 0) {
|
|
FTS_ERROR("upgrade fw bin failed");
|
|
goto err_bin;
|
|
}
|
|
|
|
FTS_INFO("upgrade fw bin success");
|
|
|
|
err_bin:
|
|
if (fw_file_buf) {
|
|
vfree(fw_file_buf);
|
|
fw_file_buf = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
int fts_enter_test_environment(bool test_state)
|
|
{
|
|
int ret = 0;
|
|
u8 detach_flag = 0;
|
|
u32 app_offset = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("fw test download function");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upgrade/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!upg->fw || (upg->fw_length <= upg->setting_nf->app2_offset)) {
|
|
FTS_INFO("not multi-app");
|
|
return 0;
|
|
}
|
|
|
|
if (test_state) {
|
|
app_offset = upg->setting_nf->app2_offset;
|
|
}
|
|
|
|
/*download firmware*/
|
|
ret = fts_fw_download(upg->fw + app_offset, upg->fw_length, true);
|
|
if (ret < 0) {
|
|
FTS_ERROR("upgrade test FW failed");
|
|
return ret;
|
|
}
|
|
|
|
fts_msleep(50);
|
|
ret = fts_read_reg(FTS_REG_FW_MODE, &detach_flag);
|
|
FTS_INFO("regb4:0x%02x", detach_flag);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int fts_fw_resume(bool need_reset, enum FW_TYPE fw_type)
|
|
{
|
|
int ret = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
const struct firmware *fw = NULL;
|
|
char fwname[FILE_NAME_LENGTH] = { 0 };
|
|
bool get_fw_i_flag = true;
|
|
const u8 *fw_buf = NULL;
|
|
u32 fwlen = 0;
|
|
u32 app_off = 0;
|
|
|
|
FTS_INFO("fw upgrade resume function");
|
|
#if !FTS_AUTO_UPGRADE_EN
|
|
FTS_INFO("FTS_AUTO_UPGRADE_EN is disabled, not upgrade");
|
|
return 0;
|
|
#endif
|
|
|
|
if (!upg || !upg->fw) {
|
|
FTS_ERROR("upg/fw is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (FTS_FW_REQUEST_SUPPORT) {
|
|
snprintf(fwname, FILE_NAME_LENGTH, "%s%s.bin", \
|
|
FTS_FW_NAME_PREX_WITH_REQUEST, upg->module_info->vendor_name);
|
|
ret = request_firmware(&fw, fwname, upg->ts_data->dev);
|
|
if (ret == 0) {
|
|
FTS_INFO("firmware(%s) request successfully", fwname);
|
|
fw_buf = fw->data;
|
|
fwlen = fw->size;
|
|
get_fw_i_flag = false;
|
|
} else {
|
|
FTS_ERROR("%s:firmware(%s) request fail,ret=%d\n",
|
|
__func__, fwname, ret);
|
|
}
|
|
}
|
|
|
|
if (get_fw_i_flag) {
|
|
FTS_INFO("download fw from bootimage");
|
|
fw_buf = upg->fw;
|
|
fwlen = upg->fw_length;
|
|
}
|
|
|
|
if (!fw_buf || (fwlen < FTS_MIN_LEN)) {
|
|
FTS_ERROR("fw/len(%d) is invalid", fwlen);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((fw_type == FW_GESTURE) ||
|
|
((fw_type == FW_AUTO) && upg->ts_data->gesture_support && upg->ts_data->suspended)) {
|
|
/*Need download gesture firmware*/
|
|
if (fwlen <= (upg->setting_nf->app2_offset * 2)) {
|
|
FTS_INFO("not support gesture-app");
|
|
ret = 0;
|
|
goto _release_firmware;
|
|
}
|
|
FTS_INFO("get gesture-app");
|
|
app_off = upg->setting_nf->app2_offset * 2;
|
|
}
|
|
|
|
ret = fts_fw_download(fw_buf + app_off, fwlen - app_off, need_reset);
|
|
if (ret < 0) {
|
|
FTS_ERROR("upgrade fw(resume) failed");
|
|
goto _release_firmware;
|
|
}
|
|
|
|
ret = 0;
|
|
_release_firmware:
|
|
if (FTS_FW_REQUEST_SUPPORT) {
|
|
if (fw != NULL) {
|
|
release_firmware(fw);
|
|
fw = NULL;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* true:fw is normal fw*/
|
|
static bool fts_check_fw_normal(void)
|
|
{
|
|
int i = 0;
|
|
int max_retries = FTS_MAX_RETRIES_READID_RESUME;
|
|
u8 val = 0;
|
|
u8 boot_state = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
struct ft_chip_t *chip_id = &upg->ts_data->ic_info.ids;
|
|
|
|
for (i = 0; i < max_retries; i++) {
|
|
fts_read_reg(FTS_REG_CHIP_ID, &val);
|
|
if ((val == chip_id->chip_idh) || (fts_check_cid(upg->ts_data, val) == 0)) {
|
|
FTS_INFO("TP Ready,Read ID=0x%02x", val);
|
|
#if (FTS_MULTI_FW_NUM > 1)
|
|
fts_read_reg(FTS_REG_FW_MODE, &val);
|
|
if ((FW_MODE_FACTORY == val) || (FW_MODE_GESTURE == val)) {
|
|
FTS_INFO("FW(%x) need upgrade", val);
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
} else {
|
|
upg->ts_data->fw_is_running = false;
|
|
fts_read_reg(FTS_CMD_READ_BOOT_STATE, &boot_state);
|
|
FTS_INFO("Read BOOT state=0x%02x", boot_state);
|
|
if ((boot_state == upg->setting_nf->upgsts_boot) && (0 == fts_check_bootid())) {
|
|
FTS_INFO("boot state:0x%x,need upgrade", boot_state);
|
|
upg->ts_data->fw_is_running = true;
|
|
return false;
|
|
}
|
|
upg->ts_data->fw_is_running = true;
|
|
}
|
|
|
|
if ((i + 1) < max_retries) fts_msleep((i + 1) * 20);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int fts_enter_gesture_fw(void)
|
|
{
|
|
u8 fw_mode = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_FUNC_ENTER();
|
|
if (fts_fw_resume(true, FW_GESTURE) == 0) {
|
|
fts_tp_state_recovery(upg->ts_data);
|
|
fts_read_reg(FTS_REG_FW_MODE, &fw_mode);
|
|
FTS_INFO("FW Mode:0x%02x", fw_mode);
|
|
} else {
|
|
FTS_ERROR("download gesture firmware failed");
|
|
}
|
|
FTS_FUNC_EXIT();
|
|
return 0;
|
|
}
|
|
|
|
int fts_enter_normal_fw(void)
|
|
{
|
|
FTS_FUNC_ENTER();
|
|
if (fts_check_fw_normal()) {
|
|
FTS_INFO("FW works normally");
|
|
} else {
|
|
if (fts_fw_resume(true, FW_NORMAL) == 0) {
|
|
fts_wait_tp_to_valid();
|
|
} else {
|
|
FTS_ERROR("download normal firmware failed");
|
|
}
|
|
}
|
|
FTS_FUNC_EXIT();
|
|
return 0;
|
|
}
|
|
|
|
/* work thread for TP driver to recover FW when TP FW is lost */
|
|
static void fts_fwrecover_work(struct work_struct *work)
|
|
{
|
|
u8 boot_state = 0;
|
|
struct fts_upgrade *upg = container_of(work, struct fts_upgrade, fwrecover_work);
|
|
|
|
FTS_FUNC_ENTER();
|
|
upg->ts_data->fw_is_running = false;
|
|
fts_read_reg(FTS_CMD_READ_BOOT_STATE, &boot_state);
|
|
if ((boot_state == upg->setting_nf->upgsts_boot) && (0 == fts_check_bootid())) {
|
|
FTS_INFO("abnormal situation,to download fw");
|
|
fts_fw_resume(false, FW_AUTO);
|
|
fts_tp_state_recovery(upg->ts_data);
|
|
FTS_INFO("FW recovery pass");
|
|
}
|
|
upg->ts_data->fw_is_running = true;
|
|
FTS_FUNC_EXIT();
|
|
}
|
|
|
|
int fts_fw_recovery(void)
|
|
{
|
|
int ret = 0;
|
|
u8 boot_state = 0;
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("check if boot recovery");
|
|
if (!upg || !upg->ts_data || !upg->setting_nf) {
|
|
FTS_ERROR("upg/ts_data/setting_nf is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!upg->ts_data->ts_workqueue || !upg->fwrecover_work.func) {
|
|
FTS_ERROR("ts_workqueue/work.func is NULL");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return -EINVAL;
|
|
}
|
|
|
|
upg->ts_data->fw_is_running = false;
|
|
ret = fts_check_bootid();
|
|
if (ret < 0) {
|
|
FTS_ERROR("check boot id fail");
|
|
upg->ts_data->fw_is_running = true;
|
|
return ret;
|
|
}
|
|
|
|
ret = fts_read_reg(FTS_CMD_READ_BOOT_STATE, &boot_state);
|
|
if (ret < 0) {
|
|
FTS_ERROR("read boot state failed, ret=%d", ret);
|
|
upg->ts_data->fw_is_running = true;
|
|
return ret;
|
|
}
|
|
|
|
if (boot_state != upg->setting_nf->upgsts_boot) {
|
|
FTS_INFO("not in boot mode(0x%x),exit", boot_state);
|
|
upg->ts_data->fw_is_running = true;
|
|
return -EIO;
|
|
}
|
|
|
|
FTS_INFO("abnormal situation,need download fw");
|
|
queue_work(upg->ts_data->ts_workqueue, &upg->fwrecover_work);
|
|
return 0;
|
|
}
|
|
|
|
/* work thread for LCD driver to call fw loading of TP driver */
|
|
static void fts_fwload_work(struct work_struct *work)
|
|
{
|
|
u8 chip_id = 0xFF;
|
|
|
|
FTS_FUNC_ENTER();
|
|
fts_fw_resume(true, FW_NORMAL);
|
|
fts_read_reg(FTS_REG_CHIP_ID, &chip_id);
|
|
FTS_INFO("read chip id:0x%02x", chip_id);
|
|
FTS_FUNC_EXIT();
|
|
}
|
|
|
|
#ifdef IDC_LOADFW_IN_LCD_DRIVER
|
|
/* Only for LCD driver to call, only for IDC chip */
|
|
int fts_load_fw_init(void)
|
|
{
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
FTS_INFO("LCD driver calls FW loading function of TP driver.");
|
|
if (!upg || !upg->ts_data) {
|
|
FTS_ERROR("upg/ts_data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!upg->ts_data->ts_workqueue || !upg->fwload_work.func) {
|
|
FTS_ERROR("ts_workqueue/work.func is NULL, can't upgrade");
|
|
return -EINVAL;
|
|
}
|
|
|
|
queue_work(upg->ts_data->ts_workqueue, &upg->fwload_work);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(fts_load_fw_init);
|
|
#endif
|
|
|
|
static int fts_fwupg_get_module_info(struct fts_upgrade *upg)
|
|
{
|
|
int i = 0;
|
|
struct upgrade_module *info = &module_list[0];
|
|
|
|
if (!upg || !upg->ts_data) {
|
|
FTS_ERROR("upg/ts_data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (FTS_GET_MODULE_NUM > 1) {
|
|
FTS_INFO("module id:%04x", upg->module_id);
|
|
for (i = 0; i < FTS_GET_MODULE_NUM; i++) {
|
|
info = &module_list[i];
|
|
if (upg->module_id == info->id) {
|
|
FTS_INFO("module id match, get fw file successfully");
|
|
break;
|
|
}
|
|
}
|
|
if (i >= FTS_GET_MODULE_NUM) {
|
|
FTS_ERROR("no module id match, don't get file");
|
|
return -ENODATA;
|
|
}
|
|
}
|
|
|
|
upg->module_info = info;
|
|
return 0;
|
|
}
|
|
|
|
static int fts_get_fw_file_via_request_firmware(struct fts_upgrade *upg)
|
|
{
|
|
int ret = 0;
|
|
const struct firmware *fw = NULL;
|
|
u8 *tmpbuf = NULL;
|
|
char fwname[FILE_NAME_LENGTH] = { 0 };
|
|
|
|
snprintf(fwname, FILE_NAME_LENGTH, "%s%s.bin", \
|
|
FTS_FW_NAME_PREX_WITH_REQUEST, \
|
|
upg->module_info->vendor_name);
|
|
|
|
ret = request_firmware(&fw, fwname, upg->ts_data->dev);
|
|
if (0 == ret) {
|
|
FTS_INFO("firmware(%s) request successfully", fwname);
|
|
tmpbuf = vmalloc(fw->size);
|
|
if (NULL == tmpbuf) {
|
|
FTS_ERROR("fw buffer vmalloc fail");
|
|
ret = -ENOMEM;
|
|
} else {
|
|
memcpy(tmpbuf, fw->data, fw->size);
|
|
upg->fw = tmpbuf;
|
|
upg->fw_length = fw->size;
|
|
upg->fw_from_request = 1;
|
|
}
|
|
} else {
|
|
FTS_INFO("firmware(%s) request fail,ret=%d", fwname, ret);
|
|
}
|
|
|
|
if (fw != NULL) {
|
|
release_firmware(fw);
|
|
fw = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fts_get_fw_file_via_i(struct fts_upgrade *upg)
|
|
{
|
|
upg->fw = upg->module_info->fw_file;
|
|
upg->fw_length = upg->module_info->fw_len;
|
|
upg->fw_from_request = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Name: fts_fwupg_get_fw_file
|
|
* Brief: get fw image/file,
|
|
* If support muitl modules, please set FTS_GET_MODULE_NUM, and FTS_-
|
|
* MODULE_ID/FTS_MODULE_NAME;
|
|
* If get fw via .i file, please set FTS_FW_REQUEST_SUPPORT=0, and F-
|
|
* TS_MODULE_ID; will use module id to distingwish different modules;
|
|
* If get fw via reques_firmware(), please set FTS_FW_REQUEST_SUPPORT
|
|
* =1, and FTS_MODULE_NAME; fw file name will be composed of "focalt-
|
|
* ech_ts_fw_" & FTS_MODULE_NAME;
|
|
*
|
|
* If have flash, module_id=vendor_id, If non-flash,module_id need
|
|
* transfer from LCD driver(gpio or lcm_id or ...);
|
|
* Input:
|
|
* Output:
|
|
* Return: return 0 if success, otherwise return error code
|
|
*****************************************************************************/
|
|
static int fts_fwupg_get_fw_file(struct fts_upgrade *upg)
|
|
{
|
|
int ret = 0;
|
|
bool get_fw_i_flag = false;
|
|
|
|
FTS_DEBUG("get upgrade fw file");
|
|
if (!upg || !upg->ts_data) {
|
|
FTS_ERROR("upg/ts_data is null");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = fts_fwupg_get_module_info(upg);
|
|
if ((ret < 0) || (!upg->module_info)) {
|
|
FTS_ERROR("get module info fail");
|
|
return ret;
|
|
}
|
|
|
|
if (FTS_FW_REQUEST_SUPPORT) {
|
|
fts_msleep(500);
|
|
ret = fts_get_fw_file_via_request_firmware(upg);
|
|
if (ret != 0) {
|
|
get_fw_i_flag = true;
|
|
}
|
|
} else {
|
|
get_fw_i_flag = true;
|
|
}
|
|
|
|
if (get_fw_i_flag) {
|
|
ret = fts_get_fw_file_via_i(upg);
|
|
}
|
|
|
|
FTS_INFO("upgrade fw file len:%d", upg->fw_length);
|
|
if (upg->fw_length < FTS_MIN_LEN) {
|
|
FTS_ERROR("fw file len(%d) fail", upg->fw_length);
|
|
return -ENODATA;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void fts_fwupg_work(struct work_struct *work)
|
|
{
|
|
int ret = 0;
|
|
u8 chip_id = 0;
|
|
//drv add hardware info -20240717-start
|
|
#if IS_ENABLED(CONFIG_PRIZE_HARDWARE_INFO)
|
|
u8 chip_id1 = 0;
|
|
#endif
|
|
//drv add hardware info -20240717-end
|
|
struct fts_upgrade *upg = fwupgrade;
|
|
|
|
#if !FTS_AUTO_UPGRADE_EN
|
|
FTS_INFO("FTS_AUTO_UPGRADE_EN is disabled, not upgrade when power on");
|
|
return ;
|
|
#endif
|
|
|
|
FTS_INFO("fw upgrade work function");
|
|
if (!upg || !upg->ts_data) {
|
|
FTS_ERROR("upg/ts_data is null");
|
|
return ;
|
|
}
|
|
|
|
/* get fw */
|
|
ret = fts_fwupg_get_fw_file(upg);
|
|
if (ret < 0) {
|
|
FTS_ERROR("get file fail, can't upgrade");
|
|
return ;
|
|
}
|
|
|
|
if (upg->ts_data->fw_loading) {
|
|
FTS_INFO("fw is loading, not download again");
|
|
return ;
|
|
}
|
|
|
|
ret = fts_fw_download(upg->fw, upg->fw_length, true);
|
|
if (ret < 0) {
|
|
FTS_ERROR("fw auto download failed");
|
|
} else {
|
|
fts_msleep(50);
|
|
ret = fts_read_reg(FTS_REG_CHIP_ID, &chip_id);
|
|
FTS_INFO("read chip id:0x%02x", chip_id);
|
|
//drv add hardware info -20240717-start
|
|
#if IS_ENABLED(CONFIG_PRIZE_HARDWARE_INFO)
|
|
ret = fts_read_reg(FTS_REG_FW_VER, &chip_id1);
|
|
if ((ret < 0) || (chip_id1 == 0xFF) || (chip_id1 == 0x00)){
|
|
strcpy(current_tp_info.chip, "FT8057S,Firmware version:get tp fw version fail!\n");
|
|
}
|
|
else
|
|
{
|
|
sprintf(current_tp_info.chip, "FT8725,Firmware version:0x%02x",chip_id1);
|
|
}
|
|
sprintf(current_tp_info.id,"0x%02x%02x", upg->ts_data->ic_info.ids.chip_idh,upg->ts_data->ic_info.ids.chip_idl);
|
|
strcpy(current_tp_info.vendor, "Focaltech");
|
|
sprintf(current_tp_info.more, "%d*%d",2408,1080);
|
|
#endif
|
|
//drv add hardware info -20240717-end
|
|
fts_esdcheck_switch(upg->ts_data, ENABLE);
|
|
}
|
|
}
|
|
|
|
int fts_fwupg_init(struct fts_ts_data *ts_data)
|
|
{
|
|
int i = 0;
|
|
struct upgrade_setting_nf *setting = &upgrade_setting_list[0];
|
|
int setting_count =
|
|
sizeof(upgrade_setting_list) / sizeof(upgrade_setting_list[0]);
|
|
|
|
FTS_INFO("fw upgrade init function");
|
|
if (!ts_data || !ts_data->ts_workqueue) {
|
|
FTS_ERROR("ts_data/workqueue is NULL, can't run upgrade function");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (0 == setting_count) {
|
|
FTS_ERROR("no upgrade settings in tp driver, init fail");
|
|
return -ENODATA;
|
|
}
|
|
|
|
fwupgrade = (struct fts_upgrade *)kzalloc(sizeof(*fwupgrade), GFP_KERNEL);
|
|
if (NULL == fwupgrade) {
|
|
FTS_ERROR("malloc memory for upgrade fail");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (1 == setting_count) {
|
|
fwupgrade->setting_nf = setting;
|
|
} else {
|
|
for (i = 0; i < setting_count; i++) {
|
|
setting = &upgrade_setting_list[i];
|
|
if ((setting->rom_idh == ts_data->ic_info.ids.rom_idh)
|
|
&& (setting->rom_idl == ts_data->ic_info.ids.rom_idl)) {
|
|
FTS_INFO("match upgrade setting,type(ID):0x%02x%02x",
|
|
setting->rom_idh, setting->rom_idl);
|
|
fwupgrade->setting_nf = setting;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL == fwupgrade->setting_nf) {
|
|
FTS_ERROR("no upgrade settings match, can't upgrade");
|
|
kfree(fwupgrade);
|
|
fwupgrade = NULL;
|
|
return -ENODATA;
|
|
}
|
|
|
|
fts_esdcheck_switch(ts_data, DISABLE);
|
|
fwupgrade->ts_data = ts_data;
|
|
INIT_WORK(&fwupgrade->fwupg_work, fts_fwupg_work);
|
|
INIT_WORK(&fwupgrade->fwrecover_work, fts_fwrecover_work);
|
|
INIT_WORK(&fwupgrade->fwload_work, fts_fwload_work);
|
|
queue_work(ts_data->ts_workqueue, &fwupgrade->fwupg_work);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fts_fwupg_exit(struct fts_ts_data *ts_data)
|
|
{
|
|
FTS_FUNC_ENTER();
|
|
if (fwupgrade) {
|
|
cancel_work_sync(&fwupgrade->fwupg_work);
|
|
cancel_work_sync(&fwupgrade->fwrecover_work);
|
|
cancel_work_sync(&fwupgrade->fwload_work);
|
|
if (fwupgrade->fw_from_request) {
|
|
vfree(fwupgrade->fw);
|
|
fwupgrade->fw = NULL;
|
|
}
|
|
|
|
kfree(fwupgrade);
|
|
fwupgrade = NULL;
|
|
}
|
|
FTS_FUNC_EXIT();
|
|
return 0;
|
|
}
|