input: synaptics_fw_update: Add firmware ID reading
- Fix issue of converting config id
- Support "Option 1 (bit0)" in image file header
-- Query firmware build id from image file header
Change-Id: Iabd24d662762b67de7163ad7321f95f1c58f1459
Git-commit: 7e811dcd8eaf3fc0df765335d0ef14926f325f64
Git-repo: git://github.com/synaptics-touch/synaptics-dsx-i2c.git
[amaloche@codeaurora.org: only portion of patch taken.
Custom changes were necessary to add for integration
with mainline]
Signed-off-by: Amy Maloche <amaloche@codeaurora.org>
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 986c062..dbe378c 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
+#include <linux/string.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_i2c_rmi4.h"
@@ -34,14 +35,7 @@
#define FORCE_UPDATE false
#define INSIDE_FIRMWARE_UPDATE
-#define CHECKSUM_OFFSET 0x00
-#define BOOTLOADER_VERSION_OFFSET 0x07
-#define IMAGE_SIZE_OFFSET 0x08
-#define CONFIG_SIZE_OFFSET 0x0C
-#define PRODUCT_ID_OFFSET 0x10
-#define PRODUCT_INFO_OFFSET 0x1E
#define FW_IMAGE_OFFSET 0x100
-#define PRODUCT_ID_SIZE 10
#define BOOTLOADER_ID_OFFSET 0
#define FLASH_PROPERTIES_OFFSET 2
@@ -59,10 +53,14 @@
#define BLOCK_NUMBER_OFFSET 0
#define BLOCK_DATA_OFFSET 2
-#define UI_CONFIG_AREA 0x00
-#define PERM_CONFIG_AREA 0x01
-#define BL_CONFIG_AREA 0x02
-#define DISP_CONFIG_AREA 0x03
+#define NAME_BUFFER_SIZE 128
+
+enum falsh_config_area {
+ UI_CONFIG_AREA = 0x00,
+ PERM_CONFIG_AREA = 0x01,
+ BL_CONFIG_AREA = 0x02,
+ DISP_CONFIG_AREA = 0x03
+};
enum flash_command {
CMD_WRITE_FW_BLOCK = 0x2,
@@ -70,9 +68,10 @@
CMD_READ_CONFIG_BLOCK = 0x5,
CMD_WRITE_CONFIG_BLOCK = 0x6,
CMD_ERASE_CONFIG = 0x7,
+ CMD_READ_SENSOR_ID = 0x8,
CMD_ERASE_BL_CONFIG = 0x9,
CMD_ERASE_DISP_CONFIG = 0xA,
- CMD_ENABLE_FLASH_PROG = 0xF,
+ CMD_ENABLE_FLASH_PROG = 0xF
};
enum flash_area {
@@ -81,6 +80,11 @@
CONFIG_AREA
};
+enum image_file_option {
+ OPTION_BUILD_INFO = 0,
+ OPTION_CONTAIN_BOOTLOADER = 1,
+};
+
#define SLEEP_MODE_NORMAL (0x00)
#define SLEEP_MODE_SENSOR_SLEEP (0x01)
#define SLEEP_MODE_RESERVED0 (0x02)
@@ -91,6 +95,8 @@
#define ERASE_WAIT_MS (5 * 1000)
#define RESET_WAIT_MS (500)
+#define POLLING_MODE 0
+
#define SLEEP_TIME_US 50
static ssize_t fwu_sysfs_show_image(struct file *data_file,
@@ -139,6 +145,40 @@
static int fwu_wait_for_idle(int timeout_ms);
+struct image_header_data {
+ union {
+ struct {
+ /* 0x00-0x0F */
+ unsigned char file_checksum[4];
+ unsigned char reserved_04;
+ unsigned char reserved_05;
+ unsigned char options_firmware_id:1;
+ unsigned char options_contain_bootloader:1;
+ unsigned char options_reserved:6;
+ unsigned char bootloader_version;
+ unsigned char firmware_size[4];
+ unsigned char config_size[4];
+ /* 0x10-0x1F */
+ unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
+ unsigned char reserved_1a;
+ unsigned char reserved_1b;
+ unsigned char reserved_1c;
+ unsigned char reserved_1d;
+ unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ /* 0x20-0x2F */
+ unsigned char reserved_20_2f[0x10];
+ /* 0x30-0x3F */
+ unsigned char ds_firmware_id[0x10];
+ /* 0x40-0x4F */
+ unsigned char ds_customize_info[10];
+ unsigned char reserved_4a_4f[6];
+ /* 0x50-0x53*/
+ unsigned char firmware_id[4];
+ } __packed;
+ unsigned char data[54];
+ };
+};
+
struct image_header {
unsigned int checksum;
unsigned int image_size;
@@ -147,6 +187,8 @@
unsigned char bootloader_version;
unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ unsigned int firmware_id;
+ bool is_contain_build_info;
};
struct pdt_properties {
@@ -245,6 +287,7 @@
struct f34_flash_properties flash_properties;
struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
+ char *firmware_name;
};
static struct bin_attribute dev_attr_data = {
@@ -308,18 +351,36 @@
(unsigned int)ptr[3] * 0x1000000;
}
+static unsigned int extract_uint_be(const unsigned char *ptr)
+{
+ return (unsigned int)ptr[3] +
+ (unsigned int)ptr[2] * 0x100 +
+ (unsigned int)ptr[1] * 0x10000 +
+ (unsigned int)ptr[0] * 0x1000000;
+}
+
static void parse_header(struct image_header *header,
const unsigned char *fw_image)
{
- header->checksum = extract_uint(&fw_image[CHECKSUM_OFFSET]);
- header->bootloader_version = fw_image[BOOTLOADER_VERSION_OFFSET];
- header->image_size = extract_uint(&fw_image[IMAGE_SIZE_OFFSET]);
- header->config_size = extract_uint(&fw_image[CONFIG_SIZE_OFFSET]);
- memcpy(header->product_id, &fw_image[PRODUCT_ID_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
- header->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
- memcpy(header->product_info, &fw_image[PRODUCT_INFO_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_INFO_SIZE);
+ struct image_header_data *data = (struct image_header_data *)fw_image;
+ header->checksum = extract_uint(data->file_checksum);
+ header->bootloader_version = data->bootloader_version;
+ header->image_size = extract_uint(data->firmware_size);
+ header->config_size = extract_uint(data->config_size);
+ memcpy(header->product_id, data->product_id,
+ sizeof(data->product_id));
+ header->product_id[sizeof(data->product_info)] = 0;
+ memcpy(header->product_info, data->product_info,
+ sizeof(data->product_info));
+
+ header->is_contain_build_info =
+ (data->options_firmware_id == (1 << OPTION_BUILD_INFO));
+ if (header->is_contain_build_info) {
+ header->firmware_id = extract_uint(data->firmware_id);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s Firwmare build id %d\n", __func__,
+ header->firmware_id);
+ }
#ifdef DEBUG_FW_UPDATE
dev_info(&fwu->rmi4_data->i2c_client->dev,
@@ -516,6 +577,9 @@
int count = 0;
int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
do {
+ #if POLLING_MODE
+ fwu_read_f34_flash_status();
+ #endif
if (fwu->flash_control.command == 0x00)
return 0;
@@ -533,7 +597,7 @@
return -ETIMEDOUT;
}
-static enum flash_area fwu_go_nogo(void)
+static enum flash_area fwu_go_nogo(struct image_header *header)
{
int retval = 0;
int index = 0;
@@ -569,7 +633,6 @@
goto exit;
}
-
/* device firmware id */
retval = fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f01_fd.query_base_addr + 18,
@@ -577,37 +640,45 @@
sizeof(firmware_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read firmware ID (code %d).\n", retval);
+ "%s: Failed to read firmware ID (code %d).\n",
+ __func__, retval);
goto exit;
}
firmware_id[3] = 0;
deviceFirmwareID = extract_uint(firmware_id);
/* .img firmware id */
- strptr = strnstr(fwu->rmi4_data->fw_image_name, "PR",
- sizeof(fwu->rmi4_data->fw_image_name));
- if (!strptr) {
+ if (header->is_contain_build_info) {
dev_err(&i2c_client->dev,
- "No valid PR number (PRxxxxxxx)" \
- "found in image file name...\n");
- goto exit;
+ "%s: Image option contains build info.\n",
+ __func__);
+ imageFirmwareID = header->firmware_id;
+ } else {
+ strptr = strnstr(fwu->firmware_name, "PR",
+ sizeof(fwu->firmware_name));
+ if (!strptr) {
+ dev_err(&i2c_client->dev,
+ "No valid PR number (PRxxxxxxx)" \
+ "found in image file name...\n");
+ goto exit;
+ }
+
+ strptr += 2;
+ while (strptr[index] >= '0' && strptr[index] <= '9') {
+ imagePR[index] = strptr[index];
+ index++;
+ }
+ imagePR[index] = 0;
+
+ retval = kstrtoul(imagePR, 10, &imageFirmwareID);
+ if (retval == -EINVAL) {
+ dev_err(&i2c_client->dev,
+ "invalid image firmware id...\n");
+ goto exit;
+ }
}
- strptr += 2;
- while (strptr[index] >= '0' && strptr[index] <= '9') {
- imagePR[index] = strptr[index];
- index++;
- }
- imagePR[index] = 0;
-
- retval = kstrtoul(imagePR, 10, &imageFirmwareID);
- if (retval == -EINVAL) {
- dev_err(&i2c_client->dev,
- "invalid image firmware id...\n");
- goto exit;
- }
-
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device firmware id %d, .img firmware id %d\n",
deviceFirmwareID,
(unsigned int)imageFirmwareID);
@@ -617,7 +688,8 @@
} else if (imageFirmwareID < deviceFirmwareID) {
flash_area = NONE;
dev_info(&i2c_client->dev,
- "Img fw is older than device fw. Skip fw update.\n");
+ "%s: Img fw is older than device fw. Skip fw update.\n",
+ __func__);
goto exit;
}
@@ -628,24 +700,29 @@
sizeof(config_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read config ID (code %d).\n", retval);
+ "%s: Failed to read config ID (code %d).\n",
+ __func__, retval);
flash_area = NONE;
goto exit;
}
- deviceConfigID = extract_uint(config_id);
+ deviceConfigID = extract_uint_be(config_id);
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
config_id[0], config_id[1], config_id[2], config_id[3]);
/* .img config id */
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
fwu->config_data[0],
fwu->config_data[1],
fwu->config_data[2],
fwu->config_data[3]);
- imageConfigID = extract_uint(fwu->config_data);
+ imageConfigID = extract_uint_be(fwu->config_data);
+
+ dev_dbg(&i2c_client->dev,
+ "%s: Device config ID %d, .img config ID %d\n",
+ __func__, deviceConfigID, imageConfigID);
if (imageConfigID > deviceConfigID) {
flash_area = CONFIG_AREA;
@@ -656,10 +733,10 @@
kfree(imagePR);
if (flash_area == NONE)
dev_info(&i2c_client->dev,
- "Nothing needs to be updated\n");
+ "%s: Nothing needs to be updated\n", __func__);
else
dev_info(&i2c_client->dev,
- "Update %s block\n",
+ "%s: Update %s block\n", __func__,
flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG");
return flash_area;
}
@@ -1210,7 +1287,7 @@
static int fwu_start_reflash(void)
{
- int retval;
+ int retval = 0;
struct image_header header;
const unsigned char *fw_image;
const struct firmware *fw_entry = NULL;
@@ -1229,18 +1306,30 @@
if (fwu->ext_data_source)
fw_image = fwu->ext_data_source;
else {
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Requesting firmware image %s\n",
- __func__, fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name = kcalloc(NAME_BUFFER_SIZE,
+ sizeof(char), GFP_KERNEL);
+ if (!fwu->firmware_name) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s Failed to allocate firmware name (%d).\n",
+ __func__, NAME_BUFFER_SIZE);
+ retval = -ENOMEM;
+ goto memory_exit;
+ }
+
+ snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+ fwu->rmi4_data->fw_image_name);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Requesting firmware image %s\n",
+ __func__, fwu->firmware_name);
retval = request_firmware(&fw_entry,
- fwu->rmi4_data->fw_image_name,
+ fwu->firmware_name,
&fwu->rmi4_data->i2c_client->dev);
if (retval != 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Firmware image %s not available\n",
__func__,
- fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name);
retval = -EINVAL;
goto exit;
}
@@ -1264,7 +1353,7 @@
if (fwu->ext_data_source)
flash_area = UI_FIRMWARE;
else
- flash_area = fwu_go_nogo();
+ flash_area = fwu_go_nogo(&header);
switch (flash_area) {
case NONE:
@@ -1318,6 +1407,8 @@
pr_notice("%s: End of reflash process\n", __func__);
exit:
+ kfree(fwu->firmware_name);
+memory_exit:
return retval;
}
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 16b1f8f..681822a 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -24,7 +24,7 @@
#define SYNAPTICS_DS4 (1 << 0)
#define SYNAPTICS_DS5 (1 << 1)
#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
-#define SYNAPTICS_DSX_DRIVER_VERSION 0x1004
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x1005
#include <linux/version.h>
#ifdef CONFIG_HAS_EARLYSUSPEND