forked from Minki/linux
Input: synaptics-rmi4 - add support for F34 V7 bootloader
Port firmware update code from Samsung Galaxy S7 driver into mainline framework. This patch has been tested on Synaptics S7813. Signed-off-by: Nick Dyer <nick@shmanahar.org> Tested-by: Chris Healy <cphealy@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
5d244f7eff
commit
5191d88acc
@ -8,7 +8,7 @@ rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
|
||||
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
|
||||
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
|
||||
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
|
||||
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o
|
||||
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
|
||||
rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
|
||||
rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
|
||||
|
||||
|
@ -544,7 +544,7 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
|
||||
else
|
||||
*empty_pages = 0;
|
||||
|
||||
return (data->f01_bootloader_mode || *empty_pages >= 2) ?
|
||||
return (data->bootloader_mode || *empty_pages >= 2) ?
|
||||
RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
|
||||
}
|
||||
|
||||
@ -749,41 +749,49 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
|
||||
subpacket) == subpacket;
|
||||
}
|
||||
|
||||
/* Indicates that flash programming is enabled (bootloader mode). */
|
||||
#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
|
||||
|
||||
/*
|
||||
* Given the PDT entry for F01, read the device status register to determine
|
||||
* if we're stuck in bootloader mode or not.
|
||||
*
|
||||
*/
|
||||
static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
|
||||
const struct pdt_entry *pdt)
|
||||
{
|
||||
int error;
|
||||
u8 device_status;
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int ret;
|
||||
u8 status;
|
||||
|
||||
error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
|
||||
&device_status);
|
||||
if (error) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read device status: %d.\n", error);
|
||||
return error;
|
||||
if (pdt->function_number == 0x34 && pdt->function_version > 1) {
|
||||
ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
|
||||
if (ret) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read F34 status: %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status & BIT(7))
|
||||
data->bootloader_mode = true;
|
||||
} else if (pdt->function_number == 0x01) {
|
||||
ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
|
||||
if (ret) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read F01 status: %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status & BIT(6))
|
||||
data->bootloader_mode = true;
|
||||
}
|
||||
|
||||
return RMI_F01_STATUS_BOOTLOADER(device_status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_count_irqs(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *pdt)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int *irq_count = ctx;
|
||||
int ret;
|
||||
|
||||
*irq_count += pdt->interrupt_source_count;
|
||||
if (pdt->function_number == 0x01)
|
||||
data->f01_bootloader_mode =
|
||||
rmi_check_bootloader_mode(rmi_dev, pdt);
|
||||
|
||||
ret = rmi_check_bootloader_mode(rmi_dev, pdt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return RMI_SCAN_CONTINUE;
|
||||
}
|
||||
@ -1024,13 +1032,15 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
|
||||
*/
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
|
||||
irq_count = 0;
|
||||
data->bootloader_mode = false;
|
||||
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "IRQ counting failed with code %d.\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data->f01_bootloader_mode)
|
||||
if (data->bootloader_mode)
|
||||
dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
|
||||
|
||||
data->irq_count = irq_count;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "rmi_driver.h"
|
||||
#include "rmi_f34.h"
|
||||
@ -105,6 +106,9 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
|
||||
int ret;
|
||||
|
||||
if (f34->bl_version != 5)
|
||||
return 0;
|
||||
|
||||
ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n",
|
||||
__func__, f34->v5.status, ret);
|
||||
@ -292,17 +296,24 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Only version 0 currently supported */
|
||||
if (data->f34_container->fd.function_version != 0) {
|
||||
f34 = dev_get_drvdata(&data->f34_container->dev);
|
||||
|
||||
if (f34->bl_version == 7) {
|
||||
if (data->pdt_props & HAS_BSR) {
|
||||
dev_err(dev, "%s: LTS not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (f34->bl_version != 5) {
|
||||
dev_warn(dev, "F34 V%d not supported!\n",
|
||||
data->f34_container->fd.function_version);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
f34 = dev_get_drvdata(&data->f34_container->dev);
|
||||
|
||||
/* Enter flash mode */
|
||||
ret = rmi_f34_enable_flash(f34);
|
||||
if (f34->bl_version == 7)
|
||||
ret = rmi_f34v7_start_reflash(f34, fw);
|
||||
else
|
||||
ret = rmi_f34_enable_flash(f34);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -319,7 +330,7 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!data->f01_bootloader_mode || !data->f34_container) {
|
||||
if (!data->bootloader_mode || !data->f34_container) {
|
||||
dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
@ -330,7 +341,10 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
f34 = dev_get_drvdata(&data->f34_container->dev);
|
||||
|
||||
/* Perform firmware update */
|
||||
ret = rmi_f34_update_firmware(f34, fw);
|
||||
if (f34->bl_version == 7)
|
||||
ret = rmi_f34v7_do_reflash(f34, fw);
|
||||
else
|
||||
ret = rmi_f34_update_firmware(f34, fw);
|
||||
|
||||
dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
|
||||
|
||||
@ -363,6 +377,9 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
const struct firmware *fw);
|
||||
|
||||
static ssize_t rmi_driver_update_fw_store(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
const char *buf, size_t count)
|
||||
@ -411,6 +428,7 @@ static int rmi_f34_probe(struct rmi_function *fn)
|
||||
struct f34_data *f34;
|
||||
unsigned char f34_queries[9];
|
||||
bool has_config_id;
|
||||
u8 version = fn->fd.function_version;
|
||||
int ret;
|
||||
|
||||
f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
|
||||
@ -420,6 +438,14 @@ static int rmi_f34_probe(struct rmi_function *fn)
|
||||
f34->fn = fn;
|
||||
dev_set_drvdata(&fn->dev, f34);
|
||||
|
||||
/* v5 code only supported version 0, try V7 probe */
|
||||
if (version > 0)
|
||||
return rmi_f34v7_probe(f34);
|
||||
else if (version != 0)
|
||||
return -ENODEV;
|
||||
|
||||
f34->bl_version = 5;
|
||||
|
||||
ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
|
||||
f34_queries, sizeof(f34_queries));
|
||||
if (ret) {
|
||||
|
@ -33,6 +33,216 @@
|
||||
|
||||
#define F34_BOOTLOADER_ID_LEN 2
|
||||
|
||||
/* F34 V7 defines */
|
||||
#define V7_FLASH_STATUS_OFFSET 0
|
||||
#define V7_PARTITION_ID_OFFSET 1
|
||||
#define V7_BLOCK_NUMBER_OFFSET 2
|
||||
#define V7_TRANSFER_LENGTH_OFFSET 3
|
||||
#define V7_COMMAND_OFFSET 4
|
||||
#define V7_PAYLOAD_OFFSET 5
|
||||
#define V7_BOOTLOADER_ID_OFFSET 1
|
||||
|
||||
#define IMAGE_HEADER_VERSION_10 0x10
|
||||
|
||||
#define CONFIG_ID_SIZE 32
|
||||
#define PRODUCT_ID_SIZE 10
|
||||
|
||||
#define ENABLE_WAIT_MS (1 * 1000)
|
||||
#define WRITE_WAIT_MS (3 * 1000)
|
||||
|
||||
#define MIN_SLEEP_TIME_US 50
|
||||
#define MAX_SLEEP_TIME_US 100
|
||||
|
||||
#define HAS_BSR BIT(5)
|
||||
#define HAS_CONFIG_ID BIT(3)
|
||||
#define HAS_GUEST_CODE BIT(6)
|
||||
#define HAS_DISP_CFG BIT(5)
|
||||
|
||||
/* F34 V7 commands */
|
||||
#define CMD_V7_IDLE 0
|
||||
#define CMD_V7_ENTER_BL 1
|
||||
#define CMD_V7_READ 2
|
||||
#define CMD_V7_WRITE 3
|
||||
#define CMD_V7_ERASE 4
|
||||
#define CMD_V7_ERASE_AP 5
|
||||
#define CMD_V7_SENSOR_ID 6
|
||||
|
||||
#define v7_CMD_IDLE 0
|
||||
#define v7_CMD_WRITE_FW 1
|
||||
#define v7_CMD_WRITE_CONFIG 2
|
||||
#define v7_CMD_WRITE_LOCKDOWN 3
|
||||
#define v7_CMD_WRITE_GUEST_CODE 4
|
||||
#define v7_CMD_READ_CONFIG 5
|
||||
#define v7_CMD_ERASE_ALL 6
|
||||
#define v7_CMD_ERASE_UI_FIRMWARE 7
|
||||
#define v7_CMD_ERASE_UI_CONFIG 8
|
||||
#define v7_CMD_ERASE_BL_CONFIG 9
|
||||
#define v7_CMD_ERASE_DISP_CONFIG 10
|
||||
#define v7_CMD_ERASE_FLASH_CONFIG 11
|
||||
#define v7_CMD_ERASE_GUEST_CODE 12
|
||||
#define v7_CMD_ENABLE_FLASH_PROG 13
|
||||
|
||||
#define v7_UI_CONFIG_AREA 0
|
||||
#define v7_PM_CONFIG_AREA 1
|
||||
#define v7_BL_CONFIG_AREA 2
|
||||
#define v7_DP_CONFIG_AREA 3
|
||||
#define v7_FLASH_CONFIG_AREA 4
|
||||
|
||||
/* F34 V7 partition IDs */
|
||||
#define BOOTLOADER_PARTITION 1
|
||||
#define DEVICE_CONFIG_PARTITION 2
|
||||
#define FLASH_CONFIG_PARTITION 3
|
||||
#define MANUFACTURING_BLOCK_PARTITION 4
|
||||
#define GUEST_SERIALIZATION_PARTITION 5
|
||||
#define GLOBAL_PARAMETERS_PARTITION 6
|
||||
#define CORE_CODE_PARTITION 7
|
||||
#define CORE_CONFIG_PARTITION 8
|
||||
#define GUEST_CODE_PARTITION 9
|
||||
#define DISPLAY_CONFIG_PARTITION 10
|
||||
|
||||
/* F34 V7 container IDs */
|
||||
#define TOP_LEVEL_CONTAINER 0
|
||||
#define UI_CONTAINER 1
|
||||
#define UI_CONFIG_CONTAINER 2
|
||||
#define BL_CONTAINER 3
|
||||
#define BL_IMAGE_CONTAINER 4
|
||||
#define BL_CONFIG_CONTAINER 5
|
||||
#define BL_LOCKDOWN_INFO_CONTAINER 6
|
||||
#define PERMANENT_CONFIG_CONTAINER 7
|
||||
#define GUEST_CODE_CONTAINER 8
|
||||
#define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9
|
||||
#define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10
|
||||
#define RMI_SELF_DISCOVERY_CONTAINER 11
|
||||
#define RMI_PAGE_CONTENT_CONTAINER 12
|
||||
#define GENERAL_INFORMATION_CONTAINER 13
|
||||
#define DEVICE_CONFIG_CONTAINER 14
|
||||
#define FLASH_CONFIG_CONTAINER 15
|
||||
#define GUEST_SERIALIZATION_CONTAINER 16
|
||||
#define GLOBAL_PARAMETERS_CONTAINER 17
|
||||
#define CORE_CODE_CONTAINER 18
|
||||
#define CORE_CONFIG_CONTAINER 19
|
||||
#define DISPLAY_CONFIG_CONTAINER 20
|
||||
|
||||
struct f34v7_query_1_7 {
|
||||
u8 bl_minor_revision; /* query 1 */
|
||||
u8 bl_major_revision;
|
||||
__le32 bl_fw_id; /* query 2 */
|
||||
u8 minimum_write_size; /* query 3 */
|
||||
__le16 block_size;
|
||||
__le16 flash_page_size;
|
||||
__le16 adjustable_partition_area_size; /* query 4 */
|
||||
__le16 flash_config_length; /* query 5 */
|
||||
__le16 payload_length; /* query 6 */
|
||||
u8 partition_support[4]; /* query 7 */
|
||||
} __packed;
|
||||
|
||||
struct f34v7_data_1_5 {
|
||||
u8 partition_id;
|
||||
__le16 block_offset;
|
||||
__le16 transfer_length;
|
||||
u8 command;
|
||||
u8 payload[2];
|
||||
} __packed;
|
||||
|
||||
struct block_data {
|
||||
const void *data;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct partition_table {
|
||||
u8 partition_id;
|
||||
u8 byte_1_reserved;
|
||||
__le16 partition_length;
|
||||
__le16 start_physical_address;
|
||||
__le16 partition_properties;
|
||||
} __packed;
|
||||
|
||||
struct physical_address {
|
||||
u16 ui_firmware;
|
||||
u16 ui_config;
|
||||
u16 dp_config;
|
||||
u16 guest_code;
|
||||
};
|
||||
|
||||
struct container_descriptor {
|
||||
__le32 content_checksum;
|
||||
__le16 container_id;
|
||||
u8 minor_version;
|
||||
u8 major_version;
|
||||
u8 reserved_08;
|
||||
u8 reserved_09;
|
||||
u8 reserved_0a;
|
||||
u8 reserved_0b;
|
||||
u8 container_option_flags[4];
|
||||
__le32 content_options_length;
|
||||
__le32 content_options_address;
|
||||
__le32 content_length;
|
||||
__le32 content_address;
|
||||
} __packed;
|
||||
|
||||
struct block_count {
|
||||
u16 ui_firmware;
|
||||
u16 ui_config;
|
||||
u16 dp_config;
|
||||
u16 fl_config;
|
||||
u16 pm_config;
|
||||
u16 bl_config;
|
||||
u16 lockdown;
|
||||
u16 guest_code;
|
||||
};
|
||||
|
||||
struct image_header_10 {
|
||||
__le32 checksum;
|
||||
u8 reserved_04;
|
||||
u8 reserved_05;
|
||||
u8 minor_header_version;
|
||||
u8 major_header_version;
|
||||
u8 reserved_08;
|
||||
u8 reserved_09;
|
||||
u8 reserved_0a;
|
||||
u8 reserved_0b;
|
||||
__le32 top_level_container_start_addr;
|
||||
};
|
||||
|
||||
struct image_metadata {
|
||||
bool contains_firmware_id;
|
||||
bool contains_bootloader;
|
||||
bool contains_display_cfg;
|
||||
bool contains_guest_code;
|
||||
bool contains_flash_config;
|
||||
unsigned int firmware_id;
|
||||
unsigned int checksum;
|
||||
unsigned int bootloader_size;
|
||||
unsigned int display_cfg_offset;
|
||||
unsigned char bl_version;
|
||||
unsigned char product_id[PRODUCT_ID_SIZE + 1];
|
||||
unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
|
||||
struct block_data bootloader;
|
||||
struct block_data ui_firmware;
|
||||
struct block_data ui_config;
|
||||
struct block_data dp_config;
|
||||
struct block_data fl_config;
|
||||
struct block_data bl_config;
|
||||
struct block_data guest_code;
|
||||
struct block_data lockdown;
|
||||
struct block_count blkcount;
|
||||
struct physical_address phyaddr;
|
||||
};
|
||||
|
||||
struct register_offset {
|
||||
u8 properties;
|
||||
u8 properties_2;
|
||||
u8 block_size;
|
||||
u8 block_count;
|
||||
u8 gc_block_count;
|
||||
u8 flash_status;
|
||||
u8 partition_id;
|
||||
u8 block_number;
|
||||
u8 transfer_length;
|
||||
u8 flash_cmd;
|
||||
u8 payload;
|
||||
};
|
||||
|
||||
struct rmi_f34_firmware {
|
||||
__le32 checksum;
|
||||
u8 pad1[3];
|
||||
@ -56,13 +266,49 @@ struct f34v5_data {
|
||||
struct mutex flash_mutex;
|
||||
};
|
||||
|
||||
struct f34v7_data {
|
||||
bool has_display_cfg;
|
||||
bool has_guest_code;
|
||||
bool force_update;
|
||||
bool in_bl_mode;
|
||||
u8 *read_config_buf;
|
||||
size_t read_config_buf_size;
|
||||
u8 command;
|
||||
u8 flash_status;
|
||||
u16 block_size;
|
||||
u16 config_block_count;
|
||||
u16 config_size;
|
||||
u16 config_area;
|
||||
u16 flash_config_length;
|
||||
u16 payload_length;
|
||||
u8 partitions;
|
||||
u16 partition_table_bytes;
|
||||
bool new_partition_table;
|
||||
|
||||
struct register_offset off;
|
||||
struct block_count blkcount;
|
||||
struct physical_address phyaddr;
|
||||
struct image_metadata img;
|
||||
|
||||
const void *config_data;
|
||||
const void *image;
|
||||
};
|
||||
|
||||
struct f34_data {
|
||||
struct rmi_function *fn;
|
||||
|
||||
u8 bl_version;
|
||||
unsigned char bootloader_id[5];
|
||||
unsigned char configuration_id[9];
|
||||
unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
|
||||
|
||||
struct f34v5_data v5;
|
||||
union {
|
||||
struct f34v5_data v5;
|
||||
struct f34v7_data v7;
|
||||
};
|
||||
};
|
||||
|
||||
int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
|
||||
int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
|
||||
int rmi_f34v7_probe(struct f34_data *f34);
|
||||
|
||||
#endif /* _RMI_F34_H */
|
||||
|
1372
drivers/input/rmi4/rmi_f34v7.c
Normal file
1372
drivers/input/rmi4/rmi_f34v7.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -342,7 +342,7 @@ struct rmi_driver_data {
|
||||
|
||||
struct rmi_function *f01_container;
|
||||
struct rmi_function *f34_container;
|
||||
bool f01_bootloader_mode;
|
||||
bool bootloader_mode;
|
||||
|
||||
int num_of_irq_regs;
|
||||
int irq_count;
|
||||
|
Loading…
Reference in New Issue
Block a user