defender: TP: Seperate focaltech_flash.c

TP:
Download function for different touch IC is different.
Seperate flash function info common part and IC unique part

Change-Id: I31637e889e2d0cb789d53d21418e1f3a1532ae12
Signed-off-by: haojl2 <haojl2@motorola.com>
Reviewed-on: https://gerrit.mot.com/1369612
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Guobin Zhang <zhanggb@motorola.com>
Submit-Approved: Jira Key
Reviewed-on: https://gerrit.mot.com/1371168
Reviewed-by: Jianqi Yang <yangj@motorola.com>
Reviewed-on: https://gerrit.mot.com/1371912
This commit is contained in:
haojl2 2019-06-12 17:30:55 +08:00 • committed by Jialei Hao
commit 409f18bb04
5 changed files with 835 additions and 331 deletions

View file

@ -20,8 +20,10 @@ focaltech_0flash_mmi-objs += focaltech_test/focaltech_test_ini.o
ifneq ($(filter ft8719,$(CONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME)),)
EXTRA_CFLAGS += -DCONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME_FT8719
focaltech_0flash_mmi-objs += focaltech_test/supported_ic/focaltech_test_ft8719.o
focaltech_0flash_mmi-objs += focaltech_flash_ft8719.o
endif
ifneq ($(filter ft8756,$(CONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME)),)
EXTRA_CFLAGS += -DCONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME_FT8756
focaltech_0flash_mmi-objs += focaltech_test/supported_ic/focaltech_test_ft8756.o
focaltech_0flash_mmi-objs += focaltech_flash_ft8756.o
endif

View file

@ -41,9 +41,6 @@
#define FTS_FW_REQUEST_SUPPORT 1
/* Example: focaltech_ts_fw_tianma.bin */
#define FTS_FW_NAME_PREX_WITH_REQUEST ""
#define FTS_READ_BOOT_ID_TIMEOUT 3
#define FTS_FLASH_PACKET_LENGTH_SPI_LOW (4 * 1024 - 4)
#define FTS_FLASH_PACKET_LENGTH_SPI (64 * 1024)
/*****************************************************************************
* Global variable or extern global variabls/functions
@ -65,7 +62,7 @@ struct upgrade_module module_list[] = {
struct fts_upgrade *fwupgrade;
static int fts_check_bootid(void)
int fts_check_bootid(void)
{
int ret = 0;
u8 cmd = 0;
@ -87,323 +84,6 @@ static int fts_check_bootid(void)
return -EIO;
}
static int fts_fwupg_hardware_reset_to_boot(void)
{
fts_reset_proc(0);
mdelay(8);
return 0;
}
static int fts_enter_into_boot(void)
{
int ret = 0;
int i = 0;
int j = 0;
u8 cmd = 0;
FTS_INFO("enter into boot environment");
for (i = 0; i < FTS_UPGRADE_LOOP; i++) {
/* hardware tp reset to boot */
fts_fwupg_hardware_reset_to_boot();
/* enter into boot & check boot id*/
for (j = 0; j < FTS_READ_BOOT_ID_TIMEOUT; j++) {
cmd = FTS_CMD_START1;
ret = fts_write(&cmd, 1);
if (ret >= 0) {
mdelay(8);
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_pram_write(u32 saddr, const u8 *buf, u32 len)
{
int ret = 0;
int i = 0;
int j = 0;
u8 *cmd;
u32 addr = 0;
u32 offset = 0;
u32 remainder = 0;
u32 packet_number;
u32 packet_len = 0;
u32 packet_size = FTS_FLASH_PACKET_LENGTH_SPI;
bool fd_support = true;
FTS_INFO("pram write");
if (NULL == buf) {
FTS_ERROR("fw buf is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_APP)) {
FTS_ERROR("fw length(%d) fail", len);
return -EINVAL;
}
fd_support = fts_check_fast_download();
if (!fd_support)
packet_size = FTS_FLASH_PACKET_LENGTH_SPI_LOW;
cmd = kzalloc(packet_size + FTS_CMD_WRITE_LEN, GFP_KERNEL);
if (NULL == cmd) {
FTS_ERROR("malloc memory for pram write buffer fail");
return -ENOMEM;
}
packet_number = len / packet_size;
remainder = len % packet_size;
if (remainder > 0)
packet_number++;
packet_len = packet_size;
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)
mdelay(3);
}
write_pram_err:
if (cmd) {
kfree(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 };
FTS_INFO("ecc calc in tp");
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;
}
mdelay(3);
/* wait boot calculate ecc finish */
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 (0 == value[0])
break;
mdelay(1);
}
if (i >= FTS_ECC_FINISH_TIMEOUT) {
FTS_ERROR("wait ecc finish timeout");
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;
u16 i = 0;
u16 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_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;
}
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;
u16 ecc_in_host = 0;
u16 ecc_in_tp = 0;
u32 fw_start_addr = 0;
u32 fw_len = 0;
u16 code_len = 0;
u16 code_len_n = 0;
FTS_INFO("begin to write and start fw(bin len:%d)", len);
/* get 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("code len(%x %x) fail", code_len, code_len_n);
return -EINVAL;
}
fw_len = (u32)code_len;
if ((fw_len < FTS_MIN_LEN) || (fw_len > FTS_MAX_LEN_APP)) {
FTS_ERROR("fw length(%d) is invalid", fw_len);
return -EINVAL;
}
FTS_INFO("fw length in fact:%d", fw_len);
fts_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(fw_start_addr, buf, fw_len);
if (ret < 0) {
FTS_ERROR("write pram fail");
return ret;
}
/* ecc check */
ret = fts_ecc_cal_host(buf, fw_len, &ecc_in_host);
if (ret < 0) {
FTS_ERROR("ecc in host calc fail");
return ret;
}
ret = fts_ecc_cal_tp(fw_start_addr, fw_len, &ecc_in_tp);
if (ret < 0) {
FTS_ERROR("ecc in tp calc fail");
return ret;
}
FTS_INFO("ecc in tp:%04x host:%04x", ecc_in_tp, ecc_in_host);
if (ecc_in_tp != ecc_in_host) {
FTS_ERROR("ecc check fail");
return -EIO;
}
/* remap pram and run fw */
ret = fts_pram_start();
if (ret < 0) {
FTS_ERROR("pram start fail");
return ret;
}
fts_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;
@ -428,21 +108,24 @@ static int fts_fw_download(const u8 *buf, u32 len, bool need_reset)
if (0 == ret)
break;
}
if (i >= 3) {
FTS_ERROR("fw download fail");
ret = -EIO;
goto err_fw_download;
}
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(ENABLE);
#endif
ret = 0;
err_fw_download:
fts_irq_enable();
ts_data->fw_loading = 0;
if (i >= 3) {
FTS_ERROR("fw download fail");
return -EIO;
return ret;
}
return 0;
}
static int fts_read_file(char *file_name, u8 **file_buf)
{
int ret = 0;
@ -542,8 +225,8 @@ int fts_enter_test_environment(bool test_state)
struct fts_upgrade *upg = fwupgrade;
FTS_INFO("fw test download function");
if (!upg || !upg->fw) {
FTS_ERROR("upg/fw is null");
if (!upg) {
FTS_ERROR("upg is null");
return -EINVAL;
}
@ -552,7 +235,7 @@ int fts_enter_test_environment(bool test_state)
return -EINVAL;
}
if (upg->fw_length <= FTS_MAX_LEN_APP) {
if (!upg->fw || (upg->fw_length <= FTS_MAX_LEN_APP)) {
FTS_INFO("not multi-app");
return 0;
}
@ -668,10 +351,11 @@ int fts_fw_recovery(void)
ret = fts_read_reg(0xD0, &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 != 0x02) {
if (boot_state != 0x01) {
FTS_INFO("not in boot mode(0x%x),exit", boot_state);
upg->ts_data->fw_is_running = true;
return -EIO;
@ -906,6 +590,10 @@ int fts_fwupg_init(struct fts_ts_data *ts_data)
return -ENOMEM;
}
#if FTS_ESDCHECK_EN
fts_esdcheck_switch(DISABLE);
#endif
fwupgrade->ts_data = ts_data;
INIT_WORK(&ts_data->fwupg_work, fts_fwupg_work);
queue_work(ts_data->ts_workqueue, &ts_data->fwupg_work);

View file

@ -176,6 +176,8 @@ struct fts_upgrade {
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
int fts_check_bootid(void);
int fts_fw_write_start(const u8 *buf, u32 len, bool need_reset);
/*****************************************************************************
* Static function prototypes

View file

@ -0,0 +1,364 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2012-2019, 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"
/*****************************************************************************
* Static variables
*****************************************************************************/
#define FTS_READ_BOOT_ID_TIMEOUT 3
#define FTS_FLASH_PACKET_LENGTH_SPI_LOW (4 * 1024 - 4)
#define FTS_FLASH_PACKET_LENGTH_SPI (64 * 1024)
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
static int fts_fwupg_hardware_reset_to_boot(void)
{
fts_reset_proc(0);
mdelay(8);
return 0;
}
static int fts_enter_into_boot(void)
{
int ret = 0;
int i = 0;
int j = 0;
u8 cmd = 0;
FTS_INFO("enter into boot environment");
for (i = 0; i < FTS_UPGRADE_LOOP; i++) {
/* hardware tp reset to boot */
fts_fwupg_hardware_reset_to_boot();
/* enter into boot & check boot id*/
for (j = 0; j < FTS_READ_BOOT_ID_TIMEOUT; j++) {
cmd = FTS_CMD_START1;
ret = fts_write(&cmd, 1);
if (ret >= 0) {
mdelay(8);
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_pram_write(u32 saddr, const u8 *buf, u32 len)
{
int ret = 0;
int i = 0;
int j = 0;
u8 *cmd;
u32 addr = 0;
u32 offset = 0;
u32 remainder = 0;
u32 packet_number;
u32 packet_len = 0;
u32 packet_size = FTS_FLASH_PACKET_LENGTH_SPI;
bool fd_support = true;
FTS_INFO("pram write");
if (NULL == buf) {
FTS_ERROR("fw buf is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_APP)) {
FTS_ERROR("fw length(%d) fail", len);
return -EINVAL;
}
fd_support = fts_check_fast_download();
if (!fd_support)
packet_size = FTS_FLASH_PACKET_LENGTH_SPI_LOW;
cmd = kzalloc(packet_size + FTS_CMD_WRITE_LEN, GFP_KERNEL);
if (NULL == cmd) {
FTS_ERROR("malloc memory for pram write buffer fail");
return -ENOMEM;
}
packet_number = len / packet_size;
remainder = len % packet_size;
if (remainder > 0)
packet_number++;
packet_len = packet_size;
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)
mdelay(3);
}
write_pram_err:
if (cmd) {
kfree(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 };
FTS_INFO("ecc calc in tp");
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;
}
mdelay(3);
/* wait boot calculate ecc finish */
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 (0 == value[0])
break;
mdelay(1);
}
if (i >= FTS_ECC_FINISH_TIMEOUT) {
FTS_ERROR("wait ecc finish timeout");
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;
u16 i = 0;
u16 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_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;
}
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
*/
int fts_fw_write_start(const u8 *buf, u32 len, bool need_reset)
{
int ret = 0;
u16 ecc_in_host = 0;
u16 ecc_in_tp = 0;
u32 fw_start_addr = 0;
u32 fw_len = 0;
u16 code_len = 0;
u16 code_len_n = 0;
FTS_INFO("begin to write and start fw(bin len:%d)", len);
/* get 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("code len(%x %x) fail", code_len, code_len_n);
return -EINVAL;
}
fw_len = (u32)code_len;
if ((fw_len < FTS_MIN_LEN) || (fw_len > FTS_MAX_LEN_APP)) {
FTS_ERROR("fw length(%d) is invalid", fw_len);
return -EINVAL;
}
FTS_INFO("fw length in fact:%d", fw_len);
fts_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(fw_start_addr, buf, fw_len);
if (ret < 0) {
FTS_ERROR("write pram fail");
return ret;
}
/* ecc check */
ret = fts_ecc_cal_host(buf, fw_len, &ecc_in_host);
if (ret < 0) {
FTS_ERROR("ecc in host calc fail");
return ret;
}
ret = fts_ecc_cal_tp(fw_start_addr, fw_len, &ecc_in_tp);
if (ret < 0) {
FTS_ERROR("ecc in tp calc fail");
return ret;
}
FTS_INFO("ecc in tp:%04x host:%04x", ecc_in_tp, ecc_in_host);
if (ecc_in_tp != ecc_in_host) {
FTS_ERROR("ecc check fail");
return -EIO;
}
/* remap pram and run fw */
ret = fts_pram_start();
if (ret < 0) {
FTS_ERROR("pram start fail");
return ret;
}
fts_data->fw_is_running = true;
FTS_INFO("fw download successfully");
return 0;
}

View file

@ -0,0 +1,448 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2012-2019, 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"
/*****************************************************************************
* Static variables
*****************************************************************************/
#define FTS_READ_BOOT_ID_TIMEOUT 3
#define FTS_FLASH_PACKET_LENGTH_SPI (32 * 1024 - 16)
#define FTS_CMD_ECC_LENGTH_MAX 32766
#define FTS_ROMBOOT_CMD_ECC_FINISH_OK 0xA5
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
static int fts_fwupg_hardware_reset_to_boot(void)
{
fts_reset_proc(0);
mdelay(8);
return 0;
}
static int fts_enter_into_boot(void)
{
int ret = 0;
int i = 0;
int j = 0;
u8 cmd[2] = { 0 };
FTS_INFO("enter into boot environment");
for (i = 0; i < FTS_UPGRADE_LOOP; i++) {
/* hardware tp reset to boot */
fts_fwupg_hardware_reset_to_boot();
/* 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) {
mdelay(8);
ret = fts_check_bootid();
if (0 == ret) {
FTS_INFO("boot id check pass, retry=%d", i);
return 0;
}
}
}
}
return -EIO;
}
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;
FTS_INFO("dpram write");
if (NULL == buf) {
FTS_ERROR("fw buf is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_APP)) {
FTS_ERROR("fw length(%d) fail", len);
return -EINVAL;
}
cmd = vmalloc(packet_size + FTS_CMD_WRITE_LEN);
if (NULL == cmd) {
FTS_ERROR("malloc memory for pram write buffer fail");
return -ENOMEM;
}
memset(cmd, 0, packet_size + FTS_CMD_WRITE_LEN);
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 };
FTS_INFO("ecc calc in tp");
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;
}
mdelay(2);
/* wait boot calculate ecc finish */
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 (FTS_ROMBOOT_CMD_ECC_FINISH_OK == value[0])
break;
mdelay(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;
u16 i = 0;
u16 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_CMD_ECC_LENGTH_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;
FTS_INFO("begin to write pram app(bin len:%d)", len);
/* 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;
pram_app_size = pram_app_size * 2;
if ((pram_app_size < FTS_MIN_LEN) || (pram_app_size > FTS_MAX_LEN_APP)) {
FTS_ERROR("pram app length(%d) is invalid", pram_app_size);
return -EINVAL;
}
FTS_INFO("pram app length in fact:%d", pram_app_size);
/* write pram */
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;
FTS_INFO("begin to write dram data(bin len:%d)", len);
/* 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) * 2;
if ((dram_size <= 0) || (dram_size > FTS_MAX_LEN_APP_PARAMS)) {
FTS_ERROR("dram data length(%d) is invalid", dram_size);
return -EINVAL;
}
pram_app_size = ((u32)(((u16)buf[FTS_APP_INFO_OFFSET + 0] << 8)
+ buf[FTS_APP_INFO_OFFSET + 1])) * 2;
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;
}
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
*/
int fts_fw_write_start(const u8 *buf, u32 len, bool need_reset)
{
int ret = 0;
FTS_INFO("begin to write and start fw(bin len:%d)", len);
fts_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;
}
/* 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;
}
fts_data->fw_is_running = true;
FTS_INFO("fw download successfully");
return 0;
}