diff options
Diffstat (limited to 'tcm/synaptics_touchcom_func_base_flash.h')
-rw-r--r-- | tcm/synaptics_touchcom_func_base_flash.h | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/tcm/synaptics_touchcom_func_base_flash.h b/tcm/synaptics_touchcom_func_base_flash.h new file mode 100644 index 0000000..87d0a4e --- /dev/null +++ b/tcm/synaptics_touchcom_func_base_flash.h @@ -0,0 +1,569 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Synaptics TouchCom touchscreen driver + * + * Copyright (C) 2017-2020 Synaptics Incorporated. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. + * DOLLARS. + */ + +/** + * @file synaptics_touchcom_func_base_flash.h + * + * This file declares the common functions and structures being used in relevant + * functions of fw update. + */ + +#ifndef _SYNAPTICS_TOUCHCOM_PARSE_FW_FILES_H_ +#define _SYNAPTICS_TOUCHCOM_PARSE_FW_FILES_H_ + +#include "synaptics_touchcom_core_dev.h" + +/** + * @section: Some specific definition in the firmware file + */ +#define ID_STRING_SIZE (32) + +#define SIZE_WORDS (8) + +#define IHEX_RECORD_SIZE (14) + +#define IHEX_MAX_BLOCKS (64) + +#define IMAGE_FILE_MAGIC_VALUE (0x4818472b) + +#define FLASH_AREA_MAGIC_VALUE (0x7c05e516) + + +/** + * @section: Helper macros for firmware file parsing + */ +#define CRC32(data, length) \ + (syna_pal_crc32(~0, data, length) ^ ~0) + +#define VALUE(value) \ + (syna_pal_le2_to_uint(value)) + +#define AREA_ID_STR(area) \ + (syna_tcm_get_flash_area_string(area)) + + +/** + * @section: Area Partitions in firmware + */ +enum flash_area { + AREA_NONE = 0, + /* please add the declarations below */ + + AREA_BOOT_CODE, + AREA_BOOT_CONFIG, + AREA_APP_CODE, + AREA_APP_CODE_COPRO, + AREA_APP_CONFIG, + AREA_PROD_TEST, + AREA_DISP_CONFIG, + AREA_F35_APP_CODE, + AREA_FORCE_TUNING, + AREA_GAMMA_TUNING, + AREA_TEMPERATURE_GAMM_TUNING, + AREA_CUSTOM_LCM, + AREA_LOOKUP, + AREA_CUSTOM_OEM, + AREA_OPEN_SHORT_TUNING, + AREA_CUSTOM_OTP, + AREA_PPDT, + AREA_ROMBOOT_APP_CODE, + AREA_TOOL_BOOT_CONFIG, + + /* please add the declarations above */ + AREA_MAX, +}; +/** + * @section: String of Area Partitions in firmware + */ +static char *flash_area_str[] = { + NULL, + /* please add the declarations below */ + + "BOOT_CODE", /* AREA_BOOT_CODE */ + "BOOT_CONFIG", /* AREA_BOOT_CONFIG */ + "APP_CODE", /* AREA_APP_CODE */ + "APP_CODE_COPRO", /* AREA_APP_CODE_COPRO */ + "APP_CONFIG", /* AREA_APP_CONFIG */ + "APP_PROD_TEST", /* AREA_PROD_TEST */ + "DISPLAY", /* AREA_DISP_CONFIG */ + "F35_APP_CODE", /* AREA_F35_APP_CODE */ + "FORCE", /* AREA_FORCE_TUNING */ + "GAMMA", /* AREA_GAMMA_TUNING */ + "TEMPERATURE_GAMM",/* AREA_TEMPERATURE_GAMM_TUNING */ + "LCM", /* AREA_CUSTOM_LCM */ + "LOOKUP", /* AREA_LOOKUP */ + "OEM", /* AREA_CUSTOM_OEM */ + "OPEN_SHORT", /* AREA_OPEN_SHORT_TUNING */ + "OTP", /* AREA_CUSTOM_OTP */ + "PPDT", /* AREA_PPDT */ + "ROMBOOT_APP_CODE",/* AREA_ROMBOOT_APP_CODE */ + "TOOL_BOOT_CONFIG",/* AREA_TOOL_BOOT_CONFIG */ + + /* please add the declarations above */ + NULL +}; +/** + * @section: Header Content of app config defined + * in firmware file + */ +struct app_config_header { + unsigned short magic_value[4]; + unsigned char checksum[4]; + unsigned char length[2]; + unsigned char build_id[4]; + unsigned char customer_config_id[16]; +}; +/** + * @section: The Partition Descriptor defined + * in firmware file + */ +struct area_descriptor { + unsigned char magic_value[4]; + unsigned char id_string[16]; + unsigned char flags[4]; + unsigned char flash_addr_words[4]; + unsigned char length[4]; + unsigned char checksum[4]; +}; +/** + * @section: Structure for the Data Block defined + * in firmware file + */ +struct block_data { + bool available; + const unsigned char *data; + unsigned int size; + unsigned int flash_addr; + unsigned char id; +}; +/** + * @section: Structure for the Parsed Image File + */ +struct image_info { + struct block_data data[AREA_MAX]; +}; +/** + * @section: Header of Image File + * + * Define the header of firmware image file + */ +struct image_header { + unsigned char magic_value[4]; + unsigned char num_of_areas[4]; +}; +/** + * @section: Structure for the Parsed iHex File + */ +struct ihex_info { + unsigned int records; + unsigned char *bin; + unsigned int bin_size; + struct block_data block[IHEX_MAX_BLOCKS]; +}; + +/** + * syna_tcm_get_flash_area_string() + * + * Return the string ID of target area in the flash memory + * + * @param + * [ in] area: target flash area + * + * @return + * the string ID + */ +static inline char *syna_tcm_get_flash_area_string(enum flash_area area) +{ + if (area < AREA_MAX) + return (char *)flash_area_str[area]; + else + return ""; +} + +/** + * syna_tcm_save_flash_block_data() + * + * Save the block data of flash memory to the corresponding structure. + * + * @param + * [out] image_info: image info used for storing the block data + * [ in] area: target area + * [ in] content: content of data + * [ in] flash_addr: offset of block data + * [ in] size: size of block data + * [ in] checksum: checksum of block data + * + * @return + * on success, return 0; otherwise, negative value on error. + */ +static int syna_tcm_save_flash_block_data(struct image_info *image_info, + enum flash_area area, const unsigned char *content, + unsigned int offset, unsigned int size, unsigned int checksum) +{ + if (!image_info) { + LOGE("Invalid image_info\n"); + return _EINVAL; + } + + if (area >= AREA_MAX) { + LOGE("Invalid flash area\n"); + return _EINVAL; + } + + if (checksum != CRC32((const char *)content, size)) { + LOGE("%s checksum error, in image: 0x%x (0x%x)\n", + AREA_ID_STR(area), checksum, + CRC32((const char *)content, size)); + return _EINVAL; + } + image_info->data[area].size = size; + image_info->data[area].data = content; + image_info->data[area].flash_addr = offset; + image_info->data[area].id = (unsigned char)area; + image_info->data[area].available = true; + + LOGI("%s area - address:0x%08x (%d), size:%d\n", + AREA_ID_STR(area), offset, offset, size); + + return 0; +} + +/** + * syna_tcm_get_flash_area_id() + * + * Return the corresponding ID of flash area based on the given string + * + * @param + * [ in] str: string to look for + * + * + * @return + * if matching, return the corresponding ID; otherwise, return AREA_MAX. + */ +static enum flash_area syna_tcm_get_flash_area_id(char *str) +{ + int area; + char *target; + unsigned int len; + + for (area = AREA_MAX - 1; area >= 0; area--) { + target = AREA_ID_STR(area); + len = syna_pal_str_len(target); + + if (syna_pal_str_cmp(str, target, len) == 0) + return area; + } + + LOGW("Un-defined area string, %s\n", str); + return AREA_MAX; +} + +/** + * syna_tcm_parse_fw_image() + * + * Parse and analyze the information of each areas from the given + * firmware image. + * + * @param + * [ in] image: image file given + * [ in] image_info: data blob stored the parsed data from an image file + * + * + * @return + * on success, 0 or positive value; otherwise, negative value on error. + */ +static inline int syna_tcm_parse_fw_image(const unsigned char *image, + struct image_info *image_info) +{ + int retval = 0; + unsigned int idx; + unsigned int addr; + unsigned int offset; + unsigned int length; + unsigned int checksum; + unsigned int flash_addr; + unsigned int magic_value; + unsigned int num_of_areas; + struct image_header *header; + struct area_descriptor *descriptor; + const unsigned char *content; + enum flash_area target_area; + + if (!image) { + LOGE("No image data\n"); + return _EINVAL; + } + + if (!image_info) { + LOGE("Invalid image_info blob\n"); + return _EINVAL; + } + + syna_pal_mem_set(image_info, 0x00, sizeof(struct image_info)); + + header = (struct image_header *)image; + + magic_value = syna_pal_le4_to_uint(header->magic_value); + if (magic_value != IMAGE_FILE_MAGIC_VALUE) { + LOGE("Invalid image file magic value\n"); + return _EINVAL; + } + + offset = sizeof(struct image_header); + num_of_areas = syna_pal_le4_to_uint(header->num_of_areas); + + for (idx = 0; idx < num_of_areas; idx++) { + addr = syna_pal_le4_to_uint(image + offset); + descriptor = (struct area_descriptor *)(image + addr); + offset += 4; + + magic_value = syna_pal_le4_to_uint(descriptor->magic_value); + if (magic_value != FLASH_AREA_MAGIC_VALUE) + continue; + + length = syna_pal_le4_to_uint(descriptor->length); + content = (unsigned char *)descriptor + sizeof(*descriptor); + flash_addr = syna_pal_le4_to_uint(descriptor->flash_addr_words); + flash_addr = flash_addr * 2; + checksum = syna_pal_le4_to_uint(descriptor->checksum); + + target_area = syna_tcm_get_flash_area_id( + (char *)descriptor->id_string); + + retval = syna_tcm_save_flash_block_data(image_info, + target_area, + content, + flash_addr, + length, + checksum); + if (retval < 0) + return _EINVAL; + } + + return 0; +} + + +/** + * syna_tcm_parse_ihex_line() + * + * Parse a line in the ihex file and convert into an actual data + * + * @param + * [ in] line: a line of string stored in the ihex file + * [out] count: size of actual data + * [out] addr: address of data located + * [out] type: the type of data belonging + * [out] buf: a buffer to store the converted data + * [int] buf_size: size of buffer + * + * @return + * on success, 0 or positive value; otherwise, negative value on error. + */ +static inline int syna_tcm_parse_ihex_line(char *line, unsigned int *count, + unsigned int *addr, unsigned int *type, unsigned char *buf, + unsigned int buf_size) +{ + const int OFFSET_COUNT = 1; + const int SIZE_COUNT = 2; + const int OFFSET_ADDR = OFFSET_COUNT + SIZE_COUNT; + const int SIZE_ADDR = 4; + const int OFFSET_TYPE = OFFSET_ADDR + SIZE_ADDR; + const int SIZE_TYPE = 2; + const int OFFSET_DATA = OFFSET_TYPE + SIZE_TYPE; + const int SIZE_DATA = 2; + unsigned int pos; + + if (!line) { + LOGE("No string line\n"); + return _EINVAL; + } + + if ((!buf) || (buf_size == 0)) { + LOGE("Invalid temporary data buffer\n"); + return _EINVAL; + } + + *count = syna_pal_hex_to_uint( + line + OFFSET_COUNT, 2); + *addr = syna_pal_hex_to_uint( + line + OFFSET_ADDR, SIZE_ADDR); + *type = syna_pal_hex_to_uint( + line + OFFSET_TYPE, SIZE_TYPE); + + if (*count > buf_size) { + LOGE("Data size mismatched, required:%d, given:%d\n", + *count, buf_size); + return _EINVAL; + } + + for (pos = 0; pos < *count; pos++) + buf[pos] = (unsigned char)syna_pal_hex_to_uint( + line + (((int)(pos << 1)) + OFFSET_DATA), + SIZE_DATA); + + return 0; +} + +/** + * syna_tcm_parse_fw_ihex() + * + * Based on the firmware ihex file given , parse and convert into a binary + * firmware data to update. + * + * @param + * [ in] ihex: original ihex file + * [ in] ihex_size: size of given file + * [ in] ihex_info: data blob stored the parsed data from an ihex file. + * assume the data buffer inside was allocated + * [ in] len_per_line: length for a useful data in a line + * + * @return + * on success, 0 or positive value; otherwise, negative value on error. + */ +static inline int syna_tcm_parse_fw_ihex(const char *ihex, int ihex_size, + struct ihex_info *ihex_info, const unsigned int len_per_line) +{ + int retval; + unsigned int pos; + unsigned int record; + char *tmp = NULL; + unsigned int count; + unsigned int type; + unsigned char data[32] = { 0 }; + unsigned int addr; + unsigned int offset; + unsigned int prev_addr; + unsigned int block_idx = 0; + + if (!ihex) { + LOGE("No ihex data\n"); + return _EINVAL; + } + + if (!ihex_info) { + LOGE("Invalid ihex_info blob\n"); + return _EINVAL; + } + + if ((!ihex_info->bin) || (ihex_info->bin_size == 0)) { + LOGE("Invalid ihex_info->data\n"); + return _EINVAL; + } + + tmp = syna_pal_mem_alloc(len_per_line + 1, sizeof(char)); + if (!tmp) { + LOGE("Fail to allocate temporary buffer\n"); + return _ENOMEM; + } + + offset = 0; + addr = 0; + pos = 0; + prev_addr = 0; + + ihex_info->records = ihex_size / len_per_line; + LOGD("records = %d\n", ihex_info->records); + + for (record = 0; record < ihex_info->records; record++) { + pos = record * len_per_line; + if ((char)ihex[pos] != ':') { + LOGE("Invalid string maker at pos %d, marker:%c\n", + pos, (char)ihex[pos]); + goto exit; + } + + retval = syna_pal_mem_cpy(tmp, len_per_line, + &ihex[pos], ihex_size - pos, len_per_line); + if (retval < 0) { + LOGE("Fail to copy a line at pos %d\n", pos); + goto exit; + } + + retval = syna_tcm_parse_ihex_line(tmp, &count, &addr, &type, + data, sizeof(data)); + if (retval < 0) { + LOGE("Fail to parse line at pos %d\n", pos); + goto exit; + } + + if ((((prev_addr + 2) & 0xFFFF) != addr) && (type == 0x00)) { + block_idx = (record == 0) ? 0 : block_idx + 1; + if (block_idx >= IHEX_MAX_BLOCKS) { + LOGE("Invalid block index\n"); + goto exit; + } + + ihex_info->block[block_idx].flash_addr = + addr + offset; + ihex_info->block[block_idx].data = + &ihex_info->bin[addr + offset]; + ihex_info->block[block_idx].available = true; + } + + if (type == 0x00) { + + prev_addr = addr; + addr += offset; + + if (addr >= ihex_info->bin_size) { + LOGE("No enough size for data0 addr:0x%x(%d)\n", + addr, addr); + goto exit; + } + ihex_info->bin[addr++] = data[0]; + + if (addr >= ihex_info->bin_size) { + LOGE("No enough size for data1 addr:0x%x(%d)\n", + addr, addr); + goto exit; + } + ihex_info->bin[addr++] = data[1]; + + ihex_info->block[block_idx].size += 2; + + } else if (type == 0x02) { + offset = (data[0] << 8) + data[1]; + offset <<= 4; + } + } + + ihex_info->bin_size = addr; /* the actual size after data reordering */ + LOGN("Size of firmware binary data = %d\n", ihex_info->bin_size); + +exit: + syna_pal_mem_free((void *)tmp); + + return 0; +} + + +#endif /* end of _SYNAPTICS_TOUCHCOM_PARSE_FW_FILES_H_ */ |