diff options
author | Nick Dyer <nick@shmanahar.org> | 2016-12-11 02:27:32 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-12-12 14:26:47 -0500 |
commit | 5191d88acc688743eef56f1c598a4e4cddf6c6cd (patch) | |
tree | 719693b8e8c697a21b4f2d1c4c3f3462426dc3aa | |
parent | 5d244f7effafeaa5272ca5daa37d8b7bb17967a8 (diff) |
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>
-rw-r--r-- | drivers/input/rmi4/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/rmi4/rmi_driver.c | 56 | ||||
-rw-r--r-- | drivers/input/rmi4/rmi_f34.c | 40 | ||||
-rw-r--r-- | drivers/input/rmi4/rmi_f34.h | 250 | ||||
-rw-r--r-- | drivers/input/rmi4/rmi_f34v7.c | 1372 | ||||
-rw-r--r-- | include/linux/rmi.h | 2 |
6 files changed, 1688 insertions, 34 deletions
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index a199cbe9c27d..9aaac3dd8613 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile | |||
@@ -8,7 +8,7 @@ rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o | |||
8 | rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o | 8 | rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o |
9 | rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o | 9 | rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o |
10 | rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o | 10 | rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o |
11 | rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o | 11 | rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o |
12 | rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o | 12 | rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o |
13 | rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o | 13 | rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o |
14 | 14 | ||
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 05a3c4bc9778..cb6efe693302 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c | |||
@@ -544,7 +544,7 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, | |||
544 | else | 544 | else |
545 | *empty_pages = 0; | 545 | *empty_pages = 0; |
546 | 546 | ||
547 | return (data->f01_bootloader_mode || *empty_pages >= 2) ? | 547 | return (data->bootloader_mode || *empty_pages >= 2) ? |
548 | RMI_SCAN_DONE : RMI_SCAN_CONTINUE; | 548 | RMI_SCAN_DONE : RMI_SCAN_CONTINUE; |
549 | } | 549 | } |
550 | 550 | ||
@@ -749,41 +749,49 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, | |||
749 | subpacket) == subpacket; | 749 | subpacket) == subpacket; |
750 | } | 750 | } |
751 | 751 | ||
752 | /* Indicates that flash programming is enabled (bootloader mode). */ | ||
753 | #define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40)) | ||
754 | |||
755 | /* | ||
756 | * Given the PDT entry for F01, read the device status register to determine | ||
757 | * if we're stuck in bootloader mode or not. | ||
758 | * | ||
759 | */ | ||
760 | static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev, | 752 | static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev, |
761 | const struct pdt_entry *pdt) | 753 | const struct pdt_entry *pdt) |
762 | { | 754 | { |
763 | int error; | 755 | struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); |
764 | u8 device_status; | 756 | int ret; |
757 | u8 status; | ||
765 | 758 | ||
766 | error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start, | 759 | if (pdt->function_number == 0x34 && pdt->function_version > 1) { |
767 | &device_status); | 760 | ret = rmi_read(rmi_dev, pdt->data_base_addr, &status); |
768 | if (error) { | 761 | if (ret) { |
769 | dev_err(&rmi_dev->dev, | 762 | dev_err(&rmi_dev->dev, |
770 | "Failed to read device status: %d.\n", error); | 763 | "Failed to read F34 status: %d.\n", ret); |
771 | return error; | 764 | return ret; |
765 | } | ||
766 | |||
767 | if (status & BIT(7)) | ||
768 | data->bootloader_mode = true; | ||
769 | } else if (pdt->function_number == 0x01) { | ||
770 | ret = rmi_read(rmi_dev, pdt->data_base_addr, &status); | ||
771 | if (ret) { | ||
772 | dev_err(&rmi_dev->dev, | ||
773 | "Failed to read F01 status: %d.\n", ret); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | if (status & BIT(6)) | ||
778 | data->bootloader_mode = true; | ||
772 | } | 779 | } |
773 | 780 | ||
774 | return RMI_F01_STATUS_BOOTLOADER(device_status); | 781 | return 0; |
775 | } | 782 | } |
776 | 783 | ||
777 | static int rmi_count_irqs(struct rmi_device *rmi_dev, | 784 | static int rmi_count_irqs(struct rmi_device *rmi_dev, |
778 | void *ctx, const struct pdt_entry *pdt) | 785 | void *ctx, const struct pdt_entry *pdt) |
779 | { | 786 | { |
780 | struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); | ||
781 | int *irq_count = ctx; | 787 | int *irq_count = ctx; |
788 | int ret; | ||
782 | 789 | ||
783 | *irq_count += pdt->interrupt_source_count; | 790 | *irq_count += pdt->interrupt_source_count; |
784 | if (pdt->function_number == 0x01) | 791 | |
785 | data->f01_bootloader_mode = | 792 | ret = rmi_check_bootloader_mode(rmi_dev, pdt); |
786 | rmi_check_bootloader_mode(rmi_dev, pdt); | 793 | if (ret < 0) |
794 | return ret; | ||
787 | 795 | ||
788 | return RMI_SCAN_CONTINUE; | 796 | return RMI_SCAN_CONTINUE; |
789 | } | 797 | } |
@@ -1024,13 +1032,15 @@ int rmi_probe_interrupts(struct rmi_driver_data *data) | |||
1024 | */ | 1032 | */ |
1025 | rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__); | 1033 | rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__); |
1026 | irq_count = 0; | 1034 | irq_count = 0; |
1035 | data->bootloader_mode = false; | ||
1036 | |||
1027 | retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs); | 1037 | retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs); |
1028 | if (retval < 0) { | 1038 | if (retval < 0) { |
1029 | dev_err(dev, "IRQ counting failed with code %d.\n", retval); | 1039 | dev_err(dev, "IRQ counting failed with code %d.\n", retval); |
1030 | return retval; | 1040 | return retval; |
1031 | } | 1041 | } |
1032 | 1042 | ||
1033 | if (data->f01_bootloader_mode) | 1043 | if (data->bootloader_mode) |
1034 | dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n"); | 1044 | dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n"); |
1035 | 1045 | ||
1036 | data->irq_count = irq_count; | 1046 | data->irq_count = irq_count; |
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 01936a4a9a6c..9774dfbab9bb 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/firmware.h> | 12 | #include <linux/firmware.h> |
13 | #include <asm/unaligned.h> | 13 | #include <asm/unaligned.h> |
14 | #include <asm/unaligned.h> | 14 | #include <asm/unaligned.h> |
15 | #include <linux/bitops.h> | ||
15 | 16 | ||
16 | #include "rmi_driver.h" | 17 | #include "rmi_driver.h" |
17 | #include "rmi_f34.h" | 18 | #include "rmi_f34.h" |
@@ -105,6 +106,9 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits) | |||
105 | struct f34_data *f34 = dev_get_drvdata(&fn->dev); | 106 | struct f34_data *f34 = dev_get_drvdata(&fn->dev); |
106 | int ret; | 107 | int ret; |
107 | 108 | ||
109 | if (f34->bl_version != 5) | ||
110 | return 0; | ||
111 | |||
108 | ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); | 112 | ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); |
109 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", | 113 | rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", |
110 | __func__, f34->v5.status, ret); | 114 | __func__, f34->v5.status, ret); |
@@ -292,17 +296,24 @@ static int rmi_firmware_update(struct rmi_driver_data *data, | |||
292 | return -EINVAL; | 296 | return -EINVAL; |
293 | } | 297 | } |
294 | 298 | ||
295 | /* Only version 0 currently supported */ | 299 | f34 = dev_get_drvdata(&data->f34_container->dev); |
296 | if (data->f34_container->fd.function_version != 0) { | 300 | |
301 | if (f34->bl_version == 7) { | ||
302 | if (data->pdt_props & HAS_BSR) { | ||
303 | dev_err(dev, "%s: LTS not supported\n", __func__); | ||
304 | return -ENODEV; | ||
305 | } | ||
306 | } else if (f34->bl_version != 5) { | ||
297 | dev_warn(dev, "F34 V%d not supported!\n", | 307 | dev_warn(dev, "F34 V%d not supported!\n", |
298 | data->f34_container->fd.function_version); | 308 | data->f34_container->fd.function_version); |
299 | return -ENODEV; | 309 | return -ENODEV; |
300 | } | 310 | } |
301 | 311 | ||
302 | f34 = dev_get_drvdata(&data->f34_container->dev); | ||
303 | |||
304 | /* Enter flash mode */ | 312 | /* Enter flash mode */ |
305 | ret = rmi_f34_enable_flash(f34); | 313 | if (f34->bl_version == 7) |
314 | ret = rmi_f34v7_start_reflash(f34, fw); | ||
315 | else | ||
316 | ret = rmi_f34_enable_flash(f34); | ||
306 | if (ret) | 317 | if (ret) |
307 | return ret; | 318 | return ret; |
308 | 319 | ||
@@ -319,7 +330,7 @@ static int rmi_firmware_update(struct rmi_driver_data *data, | |||
319 | if (ret) | 330 | if (ret) |
320 | return ret; | 331 | return ret; |
321 | 332 | ||
322 | if (!data->f01_bootloader_mode || !data->f34_container) { | 333 | if (!data->bootloader_mode || !data->f34_container) { |
323 | dev_warn(dev, "%s: No F34 present or not in bootloader!\n", | 334 | dev_warn(dev, "%s: No F34 present or not in bootloader!\n", |
324 | __func__); | 335 | __func__); |
325 | return -EINVAL; | 336 | return -EINVAL; |
@@ -330,7 +341,10 @@ static int rmi_firmware_update(struct rmi_driver_data *data, | |||
330 | f34 = dev_get_drvdata(&data->f34_container->dev); | 341 | f34 = dev_get_drvdata(&data->f34_container->dev); |
331 | 342 | ||
332 | /* Perform firmware update */ | 343 | /* Perform firmware update */ |
333 | ret = rmi_f34_update_firmware(f34, fw); | 344 | if (f34->bl_version == 7) |
345 | ret = rmi_f34v7_do_reflash(f34, fw); | ||
346 | else | ||
347 | ret = rmi_f34_update_firmware(f34, fw); | ||
334 | 348 | ||
335 | dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); | 349 | dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); |
336 | 350 | ||
@@ -363,6 +377,9 @@ static int rmi_firmware_update(struct rmi_driver_data *data, | |||
363 | return ret; | 377 | return ret; |
364 | } | 378 | } |
365 | 379 | ||
380 | static int rmi_firmware_update(struct rmi_driver_data *data, | ||
381 | const struct firmware *fw); | ||
382 | |||
366 | static ssize_t rmi_driver_update_fw_store(struct device *dev, | 383 | static ssize_t rmi_driver_update_fw_store(struct device *dev, |
367 | struct device_attribute *dattr, | 384 | struct device_attribute *dattr, |
368 | const char *buf, size_t count) | 385 | const char *buf, size_t count) |
@@ -411,6 +428,7 @@ static int rmi_f34_probe(struct rmi_function *fn) | |||
411 | struct f34_data *f34; | 428 | struct f34_data *f34; |
412 | unsigned char f34_queries[9]; | 429 | unsigned char f34_queries[9]; |
413 | bool has_config_id; | 430 | bool has_config_id; |
431 | u8 version = fn->fd.function_version; | ||
414 | int ret; | 432 | int ret; |
415 | 433 | ||
416 | f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); | 434 | f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); |
@@ -420,6 +438,14 @@ static int rmi_f34_probe(struct rmi_function *fn) | |||
420 | f34->fn = fn; | 438 | f34->fn = fn; |
421 | dev_set_drvdata(&fn->dev, f34); | 439 | dev_set_drvdata(&fn->dev, f34); |
422 | 440 | ||
441 | /* v5 code only supported version 0, try V7 probe */ | ||
442 | if (version > 0) | ||
443 | return rmi_f34v7_probe(f34); | ||
444 | else if (version != 0) | ||
445 | return -ENODEV; | ||
446 | |||
447 | f34->bl_version = 5; | ||
448 | |||
423 | ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, | 449 | ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, |
424 | f34_queries, sizeof(f34_queries)); | 450 | f34_queries, sizeof(f34_queries)); |
425 | if (ret) { | 451 | if (ret) { |
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h index 6cee5282fbb4..2c21056dc375 100644 --- a/drivers/input/rmi4/rmi_f34.h +++ b/drivers/input/rmi4/rmi_f34.h | |||
@@ -33,6 +33,216 @@ | |||
33 | 33 | ||
34 | #define F34_BOOTLOADER_ID_LEN 2 | 34 | #define F34_BOOTLOADER_ID_LEN 2 |
35 | 35 | ||
36 | /* F34 V7 defines */ | ||
37 | #define V7_FLASH_STATUS_OFFSET 0 | ||
38 | #define V7_PARTITION_ID_OFFSET 1 | ||
39 | #define V7_BLOCK_NUMBER_OFFSET 2 | ||
40 | #define V7_TRANSFER_LENGTH_OFFSET 3 | ||
41 | #define V7_COMMAND_OFFSET 4 | ||
42 | #define V7_PAYLOAD_OFFSET 5 | ||
43 | #define V7_BOOTLOADER_ID_OFFSET 1 | ||
44 | |||
45 | #define IMAGE_HEADER_VERSION_10 0x10 | ||
46 | |||
47 | #define CONFIG_ID_SIZE 32 | ||
48 | #define PRODUCT_ID_SIZE 10 | ||
49 | |||
50 | #define ENABLE_WAIT_MS (1 * 1000) | ||
51 | #define WRITE_WAIT_MS (3 * 1000) | ||
52 | |||
53 | #define MIN_SLEEP_TIME_US 50 | ||
54 | #define MAX_SLEEP_TIME_US 100 | ||
55 | |||
56 | #define HAS_BSR BIT(5) | ||
57 | #define HAS_CONFIG_ID BIT(3) | ||
58 | #define HAS_GUEST_CODE BIT(6) | ||
59 | #define HAS_DISP_CFG BIT(5) | ||
60 | |||
61 | /* F34 V7 commands */ | ||
62 | #define CMD_V7_IDLE 0 | ||
63 | #define CMD_V7_ENTER_BL 1 | ||
64 | #define CMD_V7_READ 2 | ||
65 | #define CMD_V7_WRITE 3 | ||
66 | #define CMD_V7_ERASE 4 | ||
67 | #define CMD_V7_ERASE_AP 5 | ||
68 | #define CMD_V7_SENSOR_ID 6 | ||
69 | |||
70 | #define v7_CMD_IDLE 0 | ||
71 | #define v7_CMD_WRITE_FW 1 | ||
72 | #define v7_CMD_WRITE_CONFIG 2 | ||
73 | #define v7_CMD_WRITE_LOCKDOWN 3 | ||
74 | #define v7_CMD_WRITE_GUEST_CODE 4 | ||
75 | #define v7_CMD_READ_CONFIG 5 | ||
76 | #define v7_CMD_ERASE_ALL 6 | ||
77 | #define v7_CMD_ERASE_UI_FIRMWARE 7 | ||
78 | #define v7_CMD_ERASE_UI_CONFIG 8 | ||
79 | #define v7_CMD_ERASE_BL_CONFIG 9 | ||
80 | #define v7_CMD_ERASE_DISP_CONFIG 10 | ||
81 | #define v7_CMD_ERASE_FLASH_CONFIG 11 | ||
82 | #define v7_CMD_ERASE_GUEST_CODE 12 | ||
83 | #define v7_CMD_ENABLE_FLASH_PROG 13 | ||
84 | |||
85 | #define v7_UI_CONFIG_AREA 0 | ||
86 | #define v7_PM_CONFIG_AREA 1 | ||
87 | #define v7_BL_CONFIG_AREA 2 | ||
88 | #define v7_DP_CONFIG_AREA 3 | ||
89 | #define v7_FLASH_CONFIG_AREA 4 | ||
90 | |||
91 | /* F34 V7 partition IDs */ | ||
92 | #define BOOTLOADER_PARTITION 1 | ||
93 | #define DEVICE_CONFIG_PARTITION 2 | ||
94 | #define FLASH_CONFIG_PARTITION 3 | ||
95 | #define MANUFACTURING_BLOCK_PARTITION 4 | ||
96 | #define GUEST_SERIALIZATION_PARTITION 5 | ||
97 | #define GLOBAL_PARAMETERS_PARTITION 6 | ||
98 | #define CORE_CODE_PARTITION 7 | ||
99 | #define CORE_CONFIG_PARTITION 8 | ||
100 | #define GUEST_CODE_PARTITION 9 | ||
101 | #define DISPLAY_CONFIG_PARTITION 10 | ||
102 | |||
103 | /* F34 V7 container IDs */ | ||
104 | #define TOP_LEVEL_CONTAINER 0 | ||
105 | #define UI_CONTAINER 1 | ||
106 | #define UI_CONFIG_CONTAINER 2 | ||
107 | #define BL_CONTAINER 3 | ||
108 | #define BL_IMAGE_CONTAINER 4 | ||
109 | #define BL_CONFIG_CONTAINER 5 | ||
110 | #define BL_LOCKDOWN_INFO_CONTAINER 6 | ||
111 | #define PERMANENT_CONFIG_CONTAINER 7 | ||
112 | #define GUEST_CODE_CONTAINER 8 | ||
113 | #define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9 | ||
114 | #define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10 | ||
115 | #define RMI_SELF_DISCOVERY_CONTAINER 11 | ||
116 | #define RMI_PAGE_CONTENT_CONTAINER 12 | ||
117 | #define GENERAL_INFORMATION_CONTAINER 13 | ||
118 | #define DEVICE_CONFIG_CONTAINER 14 | ||
119 | #define FLASH_CONFIG_CONTAINER 15 | ||
120 | #define GUEST_SERIALIZATION_CONTAINER 16 | ||
121 | #define GLOBAL_PARAMETERS_CONTAINER 17 | ||
122 | #define CORE_CODE_CONTAINER 18 | ||
123 | #define CORE_CONFIG_CONTAINER 19 | ||
124 | #define DISPLAY_CONFIG_CONTAINER 20 | ||
125 | |||
126 | struct f34v7_query_1_7 { | ||
127 | u8 bl_minor_revision; /* query 1 */ | ||
128 | u8 bl_major_revision; | ||
129 | __le32 bl_fw_id; /* query 2 */ | ||
130 | u8 minimum_write_size; /* query 3 */ | ||
131 | __le16 block_size; | ||
132 | __le16 flash_page_size; | ||
133 | __le16 adjustable_partition_area_size; /* query 4 */ | ||
134 | __le16 flash_config_length; /* query 5 */ | ||
135 | __le16 payload_length; /* query 6 */ | ||
136 | u8 partition_support[4]; /* query 7 */ | ||
137 | } __packed; | ||
138 | |||
139 | struct f34v7_data_1_5 { | ||
140 | u8 partition_id; | ||
141 | __le16 block_offset; | ||
142 | __le16 transfer_length; | ||
143 | u8 command; | ||
144 | u8 payload[2]; | ||
145 | } __packed; | ||
146 | |||
147 | struct block_data { | ||
148 | const void *data; | ||
149 | int size; | ||
150 | }; | ||
151 | |||
152 | struct partition_table { | ||
153 | u8 partition_id; | ||
154 | u8 byte_1_reserved; | ||
155 | __le16 partition_length; | ||
156 | __le16 start_physical_address; | ||
157 | __le16 partition_properties; | ||
158 | } __packed; | ||
159 | |||
160 | struct physical_address { | ||
161 | u16 ui_firmware; | ||
162 | u16 ui_config; | ||
163 | u16 dp_config; | ||
164 | u16 guest_code; | ||
165 | }; | ||
166 | |||
167 | struct container_descriptor { | ||
168 | __le32 content_checksum; | ||
169 | __le16 container_id; | ||
170 | u8 minor_version; | ||
171 | u8 major_version; | ||
172 | u8 reserved_08; | ||
173 | u8 reserved_09; | ||
174 | u8 reserved_0a; | ||
175 | u8 reserved_0b; | ||
176 | u8 container_option_flags[4]; | ||
177 | __le32 content_options_length; | ||
178 | __le32 content_options_address; | ||
179 | __le32 content_length; | ||
180 | __le32 content_address; | ||
181 | } __packed; | ||
182 | |||
183 | struct block_count { | ||
184 | u16 ui_firmware; | ||
185 | u16 ui_config; | ||
186 | u16 dp_config; | ||
187 | u16 fl_config; | ||
188 | u16 pm_config; | ||
189 | u16 bl_config; | ||
190 | u16 lockdown; | ||
191 | u16 guest_code; | ||
192 | }; | ||
193 | |||
194 | struct image_header_10 { | ||
195 | __le32 checksum; | ||
196 | u8 reserved_04; | ||
197 | u8 reserved_05; | ||
198 | u8 minor_header_version; | ||
199 | u8 major_header_version; | ||
200 | u8 reserved_08; | ||
201 | u8 reserved_09; | ||
202 | u8 reserved_0a; | ||
203 | u8 reserved_0b; | ||
204 | __le32 top_level_container_start_addr; | ||
205 | }; | ||
206 | |||
207 | struct image_metadata { | ||
208 | bool contains_firmware_id; | ||
209 | bool contains_bootloader; | ||
210 | bool contains_display_cfg; | ||
211 | bool contains_guest_code; | ||
212 | bool contains_flash_config; | ||
213 | unsigned int firmware_id; | ||
214 | unsigned int checksum; | ||
215 | unsigned int bootloader_size; | ||
216 | unsigned int display_cfg_offset; | ||
217 | unsigned char bl_version; | ||
218 | unsigned char product_id[PRODUCT_ID_SIZE + 1]; | ||
219 | unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; | ||
220 | struct block_data bootloader; | ||
221 | struct block_data ui_firmware; | ||
222 | struct block_data ui_config; | ||
223 | struct block_data dp_config; | ||
224 | struct block_data fl_config; | ||
225 | struct block_data bl_config; | ||
226 | struct block_data guest_code; | ||
227 | struct block_data lockdown; | ||
228 | struct block_count blkcount; | ||
229 | struct physical_address phyaddr; | ||
230 | }; | ||
231 | |||
232 | struct register_offset { | ||
233 | u8 properties; | ||
234 | u8 properties_2; | ||
235 | u8 block_size; | ||
236 | u8 block_count; | ||
237 | u8 gc_block_count; | ||
238 | u8 flash_status; | ||
239 | u8 partition_id; | ||
240 | u8 block_number; | ||
241 | u8 transfer_length; | ||
242 | u8 flash_cmd; | ||
243 | u8 payload; | ||
244 | }; | ||
245 | |||
36 | struct rmi_f34_firmware { | 246 | struct rmi_f34_firmware { |
37 | __le32 checksum; | 247 | __le32 checksum; |
38 | u8 pad1[3]; | 248 | u8 pad1[3]; |
@@ -56,13 +266,49 @@ struct f34v5_data { | |||
56 | struct mutex flash_mutex; | 266 | struct mutex flash_mutex; |
57 | }; | 267 | }; |
58 | 268 | ||
269 | struct f34v7_data { | ||
270 | bool has_display_cfg; | ||
271 | bool has_guest_code; | ||
272 | bool force_update; | ||
273 | bool in_bl_mode; | ||
274 | u8 *read_config_buf; | ||
275 | size_t read_config_buf_size; | ||
276 | u8 command; | ||
277 | u8 flash_status; | ||
278 | u16 block_size; | ||
279 | u16 config_block_count; | ||
280 | u16 config_size; | ||
281 | u16 config_area; | ||
282 | u16 flash_config_length; | ||
283 | u16 payload_length; | ||
284 | u8 partitions; | ||
285 | u16 partition_table_bytes; | ||
286 | bool new_partition_table; | ||
287 | |||
288 | struct register_offset off; | ||
289 | struct block_count blkcount; | ||
290 | struct physical_address phyaddr; | ||
291 | struct image_metadata img; | ||
292 | |||
293 | const void *config_data; | ||
294 | const void *image; | ||
295 | }; | ||
296 | |||
59 | struct f34_data { | 297 | struct f34_data { |
60 | struct rmi_function *fn; | 298 | struct rmi_function *fn; |
61 | 299 | ||
300 | u8 bl_version; | ||
62 | unsigned char bootloader_id[5]; | 301 | unsigned char bootloader_id[5]; |
63 | unsigned char configuration_id[9]; | 302 | unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1]; |
64 | 303 | ||
65 | struct f34v5_data v5; | 304 | union { |
305 | struct f34v5_data v5; | ||
306 | struct f34v7_data v7; | ||
307 | }; | ||
66 | }; | 308 | }; |
67 | 309 | ||
310 | int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw); | ||
311 | int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw); | ||
312 | int rmi_f34v7_probe(struct f34_data *f34); | ||
313 | |||
68 | #endif /* _RMI_F34_H */ | 314 | #endif /* _RMI_F34_H */ |
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c new file mode 100644 index 000000000000..ca31f9539d9b --- /dev/null +++ b/drivers/input/rmi4/rmi_f34v7.c | |||
@@ -0,0 +1,1372 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, Zodiac Inflight Innovations | ||
3 | * Copyright (c) 2007-2016, Synaptics Incorporated | ||
4 | * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com> | ||
5 | * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/rmi.h> | ||
14 | #include <linux/firmware.h> | ||
15 | #include <asm/unaligned.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "rmi_driver.h" | ||
20 | #include "rmi_f34.h" | ||
21 | |||
22 | static int rmi_f34v7_read_flash_status(struct f34_data *f34) | ||
23 | { | ||
24 | u8 status; | ||
25 | u8 command; | ||
26 | int ret; | ||
27 | |||
28 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
29 | f34->fn->fd.data_base_addr + f34->v7.off.flash_status, | ||
30 | &status, | ||
31 | sizeof(status)); | ||
32 | if (ret < 0) { | ||
33 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
34 | "%s: Failed to read flash status\n", __func__); | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | f34->v7.in_bl_mode = status >> 7; | ||
39 | f34->v7.flash_status = status & 0x1f; | ||
40 | |||
41 | if (f34->v7.flash_status != 0x00) { | ||
42 | dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n", | ||
43 | __func__, f34->v7.flash_status, f34->v7.command); | ||
44 | } | ||
45 | |||
46 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
47 | f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd, | ||
48 | &command, | ||
49 | sizeof(command)); | ||
50 | if (ret < 0) { | ||
51 | dev_err(&f34->fn->dev, "%s: Failed to read flash command\n", | ||
52 | __func__); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | f34->v7.command = command; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms) | ||
62 | { | ||
63 | int count = 0; | ||
64 | int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; | ||
65 | |||
66 | do { | ||
67 | usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); | ||
68 | |||
69 | count++; | ||
70 | |||
71 | rmi_f34v7_read_flash_status(f34); | ||
72 | |||
73 | if ((f34->v7.command == v7_CMD_IDLE) | ||
74 | && (f34->v7.flash_status == 0x00)) { | ||
75 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
76 | "Idle status detected\n"); | ||
77 | return 0; | ||
78 | } | ||
79 | } while (count < timeout_count); | ||
80 | |||
81 | dev_err(&f34->fn->dev, | ||
82 | "%s: Timed out waiting for idle status\n", __func__); | ||
83 | |||
84 | return -ETIMEDOUT; | ||
85 | } | ||
86 | |||
87 | static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34, | ||
88 | u8 cmd) | ||
89 | { | ||
90 | int ret; | ||
91 | u8 base; | ||
92 | struct f34v7_data_1_5 data_1_5; | ||
93 | |||
94 | base = f34->fn->fd.data_base_addr; | ||
95 | |||
96 | memset(&data_1_5, 0, sizeof(data_1_5)); | ||
97 | |||
98 | switch (cmd) { | ||
99 | case v7_CMD_ERASE_ALL: | ||
100 | data_1_5.partition_id = CORE_CODE_PARTITION; | ||
101 | data_1_5.command = CMD_V7_ERASE_AP; | ||
102 | break; | ||
103 | case v7_CMD_ERASE_UI_FIRMWARE: | ||
104 | data_1_5.partition_id = CORE_CODE_PARTITION; | ||
105 | data_1_5.command = CMD_V7_ERASE; | ||
106 | break; | ||
107 | case v7_CMD_ERASE_BL_CONFIG: | ||
108 | data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; | ||
109 | data_1_5.command = CMD_V7_ERASE; | ||
110 | break; | ||
111 | case v7_CMD_ERASE_UI_CONFIG: | ||
112 | data_1_5.partition_id = CORE_CONFIG_PARTITION; | ||
113 | data_1_5.command = CMD_V7_ERASE; | ||
114 | break; | ||
115 | case v7_CMD_ERASE_DISP_CONFIG: | ||
116 | data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; | ||
117 | data_1_5.command = CMD_V7_ERASE; | ||
118 | break; | ||
119 | case v7_CMD_ERASE_FLASH_CONFIG: | ||
120 | data_1_5.partition_id = FLASH_CONFIG_PARTITION; | ||
121 | data_1_5.command = CMD_V7_ERASE; | ||
122 | break; | ||
123 | case v7_CMD_ERASE_GUEST_CODE: | ||
124 | data_1_5.partition_id = GUEST_CODE_PARTITION; | ||
125 | data_1_5.command = CMD_V7_ERASE; | ||
126 | break; | ||
127 | case v7_CMD_ENABLE_FLASH_PROG: | ||
128 | data_1_5.partition_id = BOOTLOADER_PARTITION; | ||
129 | data_1_5.command = CMD_V7_ENTER_BL; | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | data_1_5.payload[0] = f34->bootloader_id[0]; | ||
134 | data_1_5.payload[1] = f34->bootloader_id[1]; | ||
135 | |||
136 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
137 | base + f34->v7.off.partition_id, | ||
138 | &data_1_5, sizeof(data_1_5)); | ||
139 | if (ret < 0) { | ||
140 | dev_err(&f34->fn->dev, | ||
141 | "%s: Failed to write single transaction command\n", | ||
142 | __func__); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd) | ||
150 | { | ||
151 | int ret; | ||
152 | u8 base; | ||
153 | u8 command; | ||
154 | |||
155 | base = f34->fn->fd.data_base_addr; | ||
156 | |||
157 | switch (cmd) { | ||
158 | case v7_CMD_WRITE_FW: | ||
159 | case v7_CMD_WRITE_CONFIG: | ||
160 | case v7_CMD_WRITE_GUEST_CODE: | ||
161 | command = CMD_V7_WRITE; | ||
162 | break; | ||
163 | case v7_CMD_READ_CONFIG: | ||
164 | command = CMD_V7_READ; | ||
165 | break; | ||
166 | case v7_CMD_ERASE_ALL: | ||
167 | command = CMD_V7_ERASE_AP; | ||
168 | break; | ||
169 | case v7_CMD_ERASE_UI_FIRMWARE: | ||
170 | case v7_CMD_ERASE_BL_CONFIG: | ||
171 | case v7_CMD_ERASE_UI_CONFIG: | ||
172 | case v7_CMD_ERASE_DISP_CONFIG: | ||
173 | case v7_CMD_ERASE_FLASH_CONFIG: | ||
174 | case v7_CMD_ERASE_GUEST_CODE: | ||
175 | command = CMD_V7_ERASE; | ||
176 | break; | ||
177 | case v7_CMD_ENABLE_FLASH_PROG: | ||
178 | command = CMD_V7_ENTER_BL; | ||
179 | break; | ||
180 | default: | ||
181 | dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n", | ||
182 | __func__, cmd); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | f34->v7.command = command; | ||
187 | |||
188 | switch (cmd) { | ||
189 | case v7_CMD_ERASE_ALL: | ||
190 | case v7_CMD_ERASE_UI_FIRMWARE: | ||
191 | case v7_CMD_ERASE_BL_CONFIG: | ||
192 | case v7_CMD_ERASE_UI_CONFIG: | ||
193 | case v7_CMD_ERASE_DISP_CONFIG: | ||
194 | case v7_CMD_ERASE_FLASH_CONFIG: | ||
195 | case v7_CMD_ERASE_GUEST_CODE: | ||
196 | case v7_CMD_ENABLE_FLASH_PROG: | ||
197 | ret = rmi_f34v7_write_command_single_transaction(f34, cmd); | ||
198 | if (ret < 0) | ||
199 | return ret; | ||
200 | else | ||
201 | return 0; | ||
202 | default: | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n", | ||
207 | __func__, command); | ||
208 | |||
209 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
210 | base + f34->v7.off.flash_cmd, | ||
211 | &command, sizeof(command)); | ||
212 | if (ret < 0) { | ||
213 | dev_err(&f34->fn->dev, "%s: Failed to write flash command\n", | ||
214 | __func__); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd) | ||
222 | { | ||
223 | int ret; | ||
224 | u8 base; | ||
225 | u8 partition; | ||
226 | |||
227 | base = f34->fn->fd.data_base_addr; | ||
228 | |||
229 | switch (cmd) { | ||
230 | case v7_CMD_WRITE_FW: | ||
231 | partition = CORE_CODE_PARTITION; | ||
232 | break; | ||
233 | case v7_CMD_WRITE_CONFIG: | ||
234 | case v7_CMD_READ_CONFIG: | ||
235 | if (f34->v7.config_area == v7_UI_CONFIG_AREA) | ||
236 | partition = CORE_CONFIG_PARTITION; | ||
237 | else if (f34->v7.config_area == v7_DP_CONFIG_AREA) | ||
238 | partition = DISPLAY_CONFIG_PARTITION; | ||
239 | else if (f34->v7.config_area == v7_PM_CONFIG_AREA) | ||
240 | partition = GUEST_SERIALIZATION_PARTITION; | ||
241 | else if (f34->v7.config_area == v7_BL_CONFIG_AREA) | ||
242 | partition = GLOBAL_PARAMETERS_PARTITION; | ||
243 | else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA) | ||
244 | partition = FLASH_CONFIG_PARTITION; | ||
245 | break; | ||
246 | case v7_CMD_WRITE_GUEST_CODE: | ||
247 | partition = GUEST_CODE_PARTITION; | ||
248 | break; | ||
249 | case v7_CMD_ERASE_ALL: | ||
250 | partition = CORE_CODE_PARTITION; | ||
251 | break; | ||
252 | case v7_CMD_ERASE_BL_CONFIG: | ||
253 | partition = GLOBAL_PARAMETERS_PARTITION; | ||
254 | break; | ||
255 | case v7_CMD_ERASE_UI_CONFIG: | ||
256 | partition = CORE_CONFIG_PARTITION; | ||
257 | break; | ||
258 | case v7_CMD_ERASE_DISP_CONFIG: | ||
259 | partition = DISPLAY_CONFIG_PARTITION; | ||
260 | break; | ||
261 | case v7_CMD_ERASE_FLASH_CONFIG: | ||
262 | partition = FLASH_CONFIG_PARTITION; | ||
263 | break; | ||
264 | case v7_CMD_ERASE_GUEST_CODE: | ||
265 | partition = GUEST_CODE_PARTITION; | ||
266 | break; | ||
267 | case v7_CMD_ENABLE_FLASH_PROG: | ||
268 | partition = BOOTLOADER_PARTITION; | ||
269 | break; | ||
270 | default: | ||
271 | dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n", | ||
272 | __func__, cmd); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
277 | base + f34->v7.off.partition_id, | ||
278 | &partition, sizeof(partition)); | ||
279 | if (ret < 0) { | ||
280 | dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n", | ||
281 | __func__); | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) | ||
289 | { | ||
290 | int ret; | ||
291 | u8 base; | ||
292 | __le16 length; | ||
293 | u16 block_number = 0; | ||
294 | |||
295 | base = f34->fn->fd.data_base_addr; | ||
296 | |||
297 | f34->v7.config_area = v7_FLASH_CONFIG_AREA; | ||
298 | |||
299 | ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG); | ||
300 | if (ret < 0) | ||
301 | return ret; | ||
302 | |||
303 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
304 | base + f34->v7.off.block_number, | ||
305 | &block_number, sizeof(block_number)); | ||
306 | if (ret < 0) { | ||
307 | dev_err(&f34->fn->dev, "%s: Failed to write block number\n", | ||
308 | __func__); | ||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | put_unaligned_le16(f34->v7.flash_config_length, &length); | ||
313 | |||
314 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
315 | base + f34->v7.off.transfer_length, | ||
316 | &length, sizeof(length)); | ||
317 | if (ret < 0) { | ||
318 | dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n", | ||
319 | __func__); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG); | ||
324 | if (ret < 0) { | ||
325 | dev_err(&f34->fn->dev, "%s: Failed to write command\n", | ||
326 | __func__); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS); | ||
331 | if (ret < 0) { | ||
332 | dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n", | ||
333 | __func__); | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
338 | base + f34->v7.off.payload, | ||
339 | f34->v7.read_config_buf, | ||
340 | f34->v7.partition_table_bytes); | ||
341 | if (ret < 0) { | ||
342 | dev_err(&f34->fn->dev, "%s: Failed to read block data\n", | ||
343 | __func__); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static void rmi_f34v7_parse_partition_table(struct f34_data *f34, | ||
351 | const void *partition_table, | ||
352 | struct block_count *blkcount, | ||
353 | struct physical_address *phyaddr) | ||
354 | { | ||
355 | int i; | ||
356 | int index; | ||
357 | u16 partition_length; | ||
358 | u16 physical_address; | ||
359 | const struct partition_table *ptable; | ||
360 | |||
361 | for (i = 0; i < f34->v7.partitions; i++) { | ||
362 | index = i * 8 + 2; | ||
363 | ptable = partition_table + index; | ||
364 | partition_length = le16_to_cpu(ptable->partition_length); | ||
365 | physical_address = le16_to_cpu(ptable->start_physical_address); | ||
366 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
367 | "%s: Partition entry %d: %*ph\n", | ||
368 | __func__, i, sizeof(struct partition_table), ptable); | ||
369 | switch (ptable->partition_id & 0x1f) { | ||
370 | case CORE_CODE_PARTITION: | ||
371 | blkcount->ui_firmware = partition_length; | ||
372 | phyaddr->ui_firmware = physical_address; | ||
373 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
374 | "%s: Core code block count: %d\n", | ||
375 | __func__, blkcount->ui_firmware); | ||
376 | break; | ||
377 | case CORE_CONFIG_PARTITION: | ||
378 | blkcount->ui_config = partition_length; | ||
379 | phyaddr->ui_config = physical_address; | ||
380 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
381 | "%s: Core config block count: %d\n", | ||
382 | __func__, blkcount->ui_config); | ||
383 | break; | ||
384 | case DISPLAY_CONFIG_PARTITION: | ||
385 | blkcount->dp_config = partition_length; | ||
386 | phyaddr->dp_config = physical_address; | ||
387 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
388 | "%s: Display config block count: %d\n", | ||
389 | __func__, blkcount->dp_config); | ||
390 | break; | ||
391 | case FLASH_CONFIG_PARTITION: | ||
392 | blkcount->fl_config = partition_length; | ||
393 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
394 | "%s: Flash config block count: %d\n", | ||
395 | __func__, blkcount->fl_config); | ||
396 | break; | ||
397 | case GUEST_CODE_PARTITION: | ||
398 | blkcount->guest_code = partition_length; | ||
399 | phyaddr->guest_code = physical_address; | ||
400 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
401 | "%s: Guest code block count: %d\n", | ||
402 | __func__, blkcount->guest_code); | ||
403 | break; | ||
404 | case GUEST_SERIALIZATION_PARTITION: | ||
405 | blkcount->pm_config = partition_length; | ||
406 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
407 | "%s: Guest serialization block count: %d\n", | ||
408 | __func__, blkcount->pm_config); | ||
409 | break; | ||
410 | case GLOBAL_PARAMETERS_PARTITION: | ||
411 | blkcount->bl_config = partition_length; | ||
412 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
413 | "%s: Global parameters block count: %d\n", | ||
414 | __func__, blkcount->bl_config); | ||
415 | break; | ||
416 | case DEVICE_CONFIG_PARTITION: | ||
417 | blkcount->lockdown = partition_length; | ||
418 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
419 | "%s: Device config block count: %d\n", | ||
420 | __func__, blkcount->lockdown); | ||
421 | break; | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
426 | static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34) | ||
427 | { | ||
428 | int ret; | ||
429 | u8 base; | ||
430 | int offset; | ||
431 | u8 query_0; | ||
432 | struct f34v7_query_1_7 query_1_7; | ||
433 | |||
434 | base = f34->fn->fd.query_base_addr; | ||
435 | |||
436 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
437 | base, | ||
438 | &query_0, | ||
439 | sizeof(query_0)); | ||
440 | if (ret < 0) { | ||
441 | dev_err(&f34->fn->dev, | ||
442 | "%s: Failed to read query 0\n", __func__); | ||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | offset = (query_0 & 0x7) + 1; | ||
447 | |||
448 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
449 | base + offset, | ||
450 | &query_1_7, | ||
451 | sizeof(query_1_7)); | ||
452 | if (ret < 0) { | ||
453 | dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n", | ||
454 | __func__); | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | f34->bootloader_id[0] = query_1_7.bl_minor_revision; | ||
459 | f34->bootloader_id[1] = query_1_7.bl_major_revision; | ||
460 | |||
461 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n", | ||
462 | f34->bootloader_id[1], f34->bootloader_id[0]); | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int rmi_f34v7_read_queries(struct f34_data *f34) | ||
468 | { | ||
469 | int ret; | ||
470 | int i, j; | ||
471 | u8 base; | ||
472 | int offset; | ||
473 | u8 *ptable; | ||
474 | u8 query_0; | ||
475 | struct f34v7_query_1_7 query_1_7; | ||
476 | |||
477 | base = f34->fn->fd.query_base_addr; | ||
478 | |||
479 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
480 | base, | ||
481 | &query_0, | ||
482 | sizeof(query_0)); | ||
483 | if (ret < 0) { | ||
484 | dev_err(&f34->fn->dev, | ||
485 | "%s: Failed to read query 0\n", __func__); | ||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | offset = (query_0 & 0x07) + 1; | ||
490 | |||
491 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
492 | base + offset, | ||
493 | &query_1_7, | ||
494 | sizeof(query_1_7)); | ||
495 | if (ret < 0) { | ||
496 | dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n", | ||
497 | __func__); | ||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | f34->bootloader_id[0] = query_1_7.bl_minor_revision; | ||
502 | f34->bootloader_id[1] = query_1_7.bl_major_revision; | ||
503 | |||
504 | f34->v7.block_size = le16_to_cpu(query_1_7.block_size); | ||
505 | f34->v7.flash_config_length = | ||
506 | le16_to_cpu(query_1_7.flash_config_length); | ||
507 | f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length); | ||
508 | |||
509 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n", | ||
510 | __func__, f34->v7.block_size); | ||
511 | |||
512 | f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET; | ||
513 | f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET; | ||
514 | f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET; | ||
515 | f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; | ||
516 | f34->v7.off.flash_cmd = V7_COMMAND_OFFSET; | ||
517 | f34->v7.off.payload = V7_PAYLOAD_OFFSET; | ||
518 | |||
519 | f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG; | ||
520 | f34->v7.has_guest_code = | ||
521 | query_1_7.partition_support[1] & HAS_GUEST_CODE; | ||
522 | |||
523 | if (query_0 & HAS_CONFIG_ID) { | ||
524 | char f34_ctrl[CONFIG_ID_SIZE]; | ||
525 | int i = 0; | ||
526 | u8 *p = f34->configuration_id; | ||
527 | *p = '\0'; | ||
528 | |||
529 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
530 | f34->fn->fd.control_base_addr, | ||
531 | f34_ctrl, | ||
532 | sizeof(f34_ctrl)); | ||
533 | if (ret) | ||
534 | return ret; | ||
535 | |||
536 | /* Eat leading zeros */ | ||
537 | while (i < sizeof(f34_ctrl) && !f34_ctrl[i]) | ||
538 | i++; | ||
539 | |||
540 | for (; i < sizeof(f34_ctrl); i++) | ||
541 | p += snprintf(p, f34->configuration_id | ||
542 | + sizeof(f34->configuration_id) - p, | ||
543 | "%02X", f34_ctrl[i]); | ||
544 | |||
545 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n", | ||
546 | f34->configuration_id); | ||
547 | } | ||
548 | |||
549 | f34->v7.partitions = 0; | ||
550 | for (i = 0; i < sizeof(query_1_7.partition_support); i++) | ||
551 | for (j = 0; j < 8; j++) | ||
552 | if (query_1_7.partition_support[i] & (1 << j)) | ||
553 | f34->v7.partitions++; | ||
554 | |||
555 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n", | ||
556 | __func__, sizeof(query_1_7.partition_support), | ||
557 | query_1_7.partition_support); | ||
558 | |||
559 | |||
560 | f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2; | ||
561 | |||
562 | f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev, | ||
563 | f34->v7.partition_table_bytes, | ||
564 | GFP_KERNEL); | ||
565 | if (!f34->v7.read_config_buf) { | ||
566 | f34->v7.read_config_buf_size = 0; | ||
567 | return -ENOMEM; | ||
568 | } | ||
569 | |||
570 | f34->v7.read_config_buf_size = f34->v7.partition_table_bytes; | ||
571 | ptable = f34->v7.read_config_buf; | ||
572 | |||
573 | ret = rmi_f34v7_read_f34v7_partition_table(f34); | ||
574 | if (ret < 0) { | ||
575 | dev_err(&f34->fn->dev, "%s: Failed to read partition table\n", | ||
576 | __func__); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | rmi_f34v7_parse_partition_table(f34, ptable, | ||
581 | &f34->v7.blkcount, &f34->v7.phyaddr); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34) | ||
587 | { | ||
588 | u16 block_count; | ||
589 | |||
590 | block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size; | ||
591 | |||
592 | if (block_count != f34->v7.blkcount.ui_firmware) { | ||
593 | dev_err(&f34->fn->dev, | ||
594 | "UI firmware size mismatch: %d != %d\n", | ||
595 | block_count, f34->v7.blkcount.ui_firmware); | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | static int rmi_f34v7_check_ui_config_size(struct f34_data *f34) | ||
603 | { | ||
604 | u16 block_count; | ||
605 | |||
606 | block_count = f34->v7.img.ui_config.size / f34->v7.block_size; | ||
607 | |||
608 | if (block_count != f34->v7.blkcount.ui_config) { | ||
609 | dev_err(&f34->fn->dev, "UI config size mismatch\n"); | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int rmi_f34v7_check_dp_config_size(struct f34_data *f34) | ||
617 | { | ||
618 | u16 block_count; | ||
619 | |||
620 | block_count = f34->v7.img.dp_config.size / f34->v7.block_size; | ||
621 | |||
622 | if (block_count != f34->v7.blkcount.dp_config) { | ||
623 | dev_err(&f34->fn->dev, "Display config size mismatch\n"); | ||
624 | return -EINVAL; | ||
625 | } | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static int rmi_f34v7_check_guest_code_size(struct f34_data *f34) | ||
631 | { | ||
632 | u16 block_count; | ||
633 | |||
634 | block_count = f34->v7.img.guest_code.size / f34->v7.block_size; | ||
635 | if (block_count != f34->v7.blkcount.guest_code) { | ||
636 | dev_err(&f34->fn->dev, "Guest code size mismatch\n"); | ||
637 | return -EINVAL; | ||
638 | } | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int rmi_f34v7_check_bl_config_size(struct f34_data *f34) | ||
644 | { | ||
645 | u16 block_count; | ||
646 | |||
647 | block_count = f34->v7.img.bl_config.size / f34->v7.block_size; | ||
648 | |||
649 | if (block_count != f34->v7.blkcount.bl_config) { | ||
650 | dev_err(&f34->fn->dev, "Bootloader config size mismatch\n"); | ||
651 | return -EINVAL; | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int rmi_f34v7_erase_config(struct f34_data *f34) | ||
658 | { | ||
659 | int ret; | ||
660 | |||
661 | dev_info(&f34->fn->dev, "Erasing config...\n"); | ||
662 | |||
663 | switch (f34->v7.config_area) { | ||
664 | case v7_UI_CONFIG_AREA: | ||
665 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG); | ||
666 | if (ret < 0) | ||
667 | return ret; | ||
668 | break; | ||
669 | case v7_DP_CONFIG_AREA: | ||
670 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG); | ||
671 | if (ret < 0) | ||
672 | return ret; | ||
673 | break; | ||
674 | case v7_BL_CONFIG_AREA: | ||
675 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG); | ||
676 | if (ret < 0) | ||
677 | return ret; | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
682 | if (ret < 0) | ||
683 | return ret; | ||
684 | |||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | static int rmi_f34v7_erase_guest_code(struct f34_data *f34) | ||
689 | { | ||
690 | int ret; | ||
691 | |||
692 | dev_info(&f34->fn->dev, "Erasing guest code...\n"); | ||
693 | |||
694 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE); | ||
695 | if (ret < 0) | ||
696 | return ret; | ||
697 | |||
698 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
699 | if (ret < 0) | ||
700 | return ret; | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | static int rmi_f34v7_erase_all(struct f34_data *f34) | ||
706 | { | ||
707 | int ret; | ||
708 | |||
709 | dev_info(&f34->fn->dev, "Erasing firmware...\n"); | ||
710 | |||
711 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE); | ||
712 | if (ret < 0) | ||
713 | return ret; | ||
714 | |||
715 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
716 | if (ret < 0) | ||
717 | return ret; | ||
718 | |||
719 | f34->v7.config_area = v7_UI_CONFIG_AREA; | ||
720 | ret = rmi_f34v7_erase_config(f34); | ||
721 | if (ret < 0) | ||
722 | return ret; | ||
723 | |||
724 | if (f34->v7.has_display_cfg) { | ||
725 | f34->v7.config_area = v7_DP_CONFIG_AREA; | ||
726 | ret = rmi_f34v7_erase_config(f34); | ||
727 | if (ret < 0) | ||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | if (f34->v7.new_partition_table && f34->v7.has_guest_code) { | ||
732 | ret = rmi_f34v7_erase_guest_code(f34); | ||
733 | if (ret < 0) | ||
734 | return ret; | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, | ||
741 | u8 command) | ||
742 | { | ||
743 | int ret; | ||
744 | u8 base; | ||
745 | __le16 length; | ||
746 | u16 transfer; | ||
747 | u16 max_transfer; | ||
748 | u16 remaining = block_cnt; | ||
749 | u16 block_number = 0; | ||
750 | u16 index = 0; | ||
751 | |||
752 | base = f34->fn->fd.data_base_addr; | ||
753 | |||
754 | ret = rmi_f34v7_write_partition_id(f34, command); | ||
755 | if (ret < 0) | ||
756 | return ret; | ||
757 | |||
758 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
759 | base + f34->v7.off.block_number, | ||
760 | &block_number, sizeof(block_number)); | ||
761 | if (ret < 0) { | ||
762 | dev_err(&f34->fn->dev, "%s: Failed to write block number\n", | ||
763 | __func__); | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | max_transfer = min(f34->v7.payload_length, | ||
768 | (u16)(PAGE_SIZE / f34->v7.block_size)); | ||
769 | |||
770 | do { | ||
771 | transfer = min(remaining, max_transfer); | ||
772 | put_unaligned_le16(transfer, &length); | ||
773 | |||
774 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
775 | base + f34->v7.off.transfer_length, | ||
776 | &length, sizeof(length)); | ||
777 | if (ret < 0) { | ||
778 | dev_err(&f34->fn->dev, | ||
779 | "%s: Write transfer length fail (%d remaining)\n", | ||
780 | __func__, remaining); | ||
781 | return ret; | ||
782 | } | ||
783 | |||
784 | ret = rmi_f34v7_write_command(f34, command); | ||
785 | if (ret < 0) | ||
786 | return ret; | ||
787 | |||
788 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
789 | if (ret < 0) { | ||
790 | dev_err(&f34->fn->dev, | ||
791 | "%s: Wait for idle failed (%d blks remaining)\n", | ||
792 | __func__, remaining); | ||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
797 | base + f34->v7.off.payload, | ||
798 | &f34->v7.read_config_buf[index], | ||
799 | transfer * f34->v7.block_size); | ||
800 | if (ret < 0) { | ||
801 | dev_err(&f34->fn->dev, | ||
802 | "%s: Read block failed (%d blks remaining)\n", | ||
803 | __func__, remaining); | ||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | index += (transfer * f34->v7.block_size); | ||
808 | remaining -= transfer; | ||
809 | } while (remaining); | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, | ||
815 | const void *block_ptr, u16 block_cnt, | ||
816 | u8 command) | ||
817 | { | ||
818 | int ret; | ||
819 | u8 base; | ||
820 | __le16 length; | ||
821 | u16 transfer; | ||
822 | u16 max_transfer; | ||
823 | u16 remaining = block_cnt; | ||
824 | u16 block_number = 0; | ||
825 | |||
826 | base = f34->fn->fd.data_base_addr; | ||
827 | |||
828 | ret = rmi_f34v7_write_partition_id(f34, command); | ||
829 | if (ret < 0) | ||
830 | return ret; | ||
831 | |||
832 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
833 | base + f34->v7.off.block_number, | ||
834 | &block_number, sizeof(block_number)); | ||
835 | if (ret < 0) { | ||
836 | dev_err(&f34->fn->dev, "%s: Failed to write block number\n", | ||
837 | __func__); | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size)) | ||
842 | max_transfer = PAGE_SIZE / f34->v7.block_size; | ||
843 | else | ||
844 | max_transfer = f34->v7.payload_length; | ||
845 | |||
846 | do { | ||
847 | transfer = min(remaining, max_transfer); | ||
848 | put_unaligned_le16(transfer, &length); | ||
849 | |||
850 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
851 | base + f34->v7.off.transfer_length, | ||
852 | &length, sizeof(length)); | ||
853 | if (ret < 0) { | ||
854 | dev_err(&f34->fn->dev, | ||
855 | "%s: Write transfer length fail (%d remaining)\n", | ||
856 | __func__, remaining); | ||
857 | return ret; | ||
858 | } | ||
859 | |||
860 | ret = rmi_f34v7_write_command(f34, command); | ||
861 | if (ret < 0) | ||
862 | return ret; | ||
863 | |||
864 | ret = rmi_write_block(f34->fn->rmi_dev, | ||
865 | base + f34->v7.off.payload, | ||
866 | block_ptr, transfer * f34->v7.block_size); | ||
867 | if (ret < 0) { | ||
868 | dev_err(&f34->fn->dev, | ||
869 | "%s: Failed writing data (%d blks remaining)\n", | ||
870 | __func__, remaining); | ||
871 | return ret; | ||
872 | } | ||
873 | |||
874 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
875 | if (ret < 0) { | ||
876 | dev_err(&f34->fn->dev, | ||
877 | "%s: Failed wait for idle (%d blks remaining)\n", | ||
878 | __func__, remaining); | ||
879 | return ret; | ||
880 | } | ||
881 | |||
882 | block_ptr += (transfer * f34->v7.block_size); | ||
883 | remaining -= transfer; | ||
884 | } while (remaining); | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static int rmi_f34v7_write_config(struct f34_data *f34) | ||
890 | { | ||
891 | return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data, | ||
892 | f34->v7.config_block_count, | ||
893 | v7_CMD_WRITE_CONFIG); | ||
894 | } | ||
895 | |||
896 | static int rmi_f34v7_write_ui_config(struct f34_data *f34) | ||
897 | { | ||
898 | f34->v7.config_area = v7_UI_CONFIG_AREA; | ||
899 | f34->v7.config_data = f34->v7.img.ui_config.data; | ||
900 | f34->v7.config_size = f34->v7.img.ui_config.size; | ||
901 | f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; | ||
902 | |||
903 | return rmi_f34v7_write_config(f34); | ||
904 | } | ||
905 | |||
906 | static int rmi_f34v7_write_dp_config(struct f34_data *f34) | ||
907 | { | ||
908 | f34->v7.config_area = v7_DP_CONFIG_AREA; | ||
909 | f34->v7.config_data = f34->v7.img.dp_config.data; | ||
910 | f34->v7.config_size = f34->v7.img.dp_config.size; | ||
911 | f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; | ||
912 | |||
913 | return rmi_f34v7_write_config(f34); | ||
914 | } | ||
915 | |||
916 | static int rmi_f34v7_write_guest_code(struct f34_data *f34) | ||
917 | { | ||
918 | return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data, | ||
919 | f34->v7.img.guest_code.size / | ||
920 | f34->v7.block_size, | ||
921 | v7_CMD_WRITE_GUEST_CODE); | ||
922 | } | ||
923 | |||
924 | static int rmi_f34v7_write_flash_config(struct f34_data *f34) | ||
925 | { | ||
926 | int ret; | ||
927 | |||
928 | f34->v7.config_area = v7_FLASH_CONFIG_AREA; | ||
929 | f34->v7.config_data = f34->v7.img.fl_config.data; | ||
930 | f34->v7.config_size = f34->v7.img.fl_config.size; | ||
931 | f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; | ||
932 | |||
933 | if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) { | ||
934 | dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n", | ||
935 | __func__); | ||
936 | return -EINVAL; | ||
937 | } | ||
938 | |||
939 | ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG); | ||
940 | if (ret < 0) | ||
941 | return ret; | ||
942 | |||
943 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
944 | "%s: Erase flash config command written\n", __func__); | ||
945 | |||
946 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
947 | if (ret < 0) | ||
948 | return ret; | ||
949 | |||
950 | ret = rmi_f34v7_write_config(f34); | ||
951 | if (ret < 0) | ||
952 | return ret; | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | static int rmi_f34v7_write_partition_table(struct f34_data *f34) | ||
958 | { | ||
959 | u16 block_count; | ||
960 | int ret; | ||
961 | |||
962 | block_count = f34->v7.blkcount.bl_config; | ||
963 | f34->v7.config_area = v7_BL_CONFIG_AREA; | ||
964 | f34->v7.config_size = f34->v7.block_size * block_count; | ||
965 | devm_kfree(&f34->fn->dev, f34->v7.read_config_buf); | ||
966 | f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev, | ||
967 | f34->v7.config_size, GFP_KERNEL); | ||
968 | if (!f34->v7.read_config_buf) { | ||
969 | f34->v7.read_config_buf_size = 0; | ||
970 | return -ENOMEM; | ||
971 | } | ||
972 | |||
973 | f34->v7.read_config_buf_size = f34->v7.config_size; | ||
974 | |||
975 | ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG); | ||
976 | if (ret < 0) | ||
977 | return ret; | ||
978 | |||
979 | ret = rmi_f34v7_erase_config(f34); | ||
980 | if (ret < 0) | ||
981 | return ret; | ||
982 | |||
983 | ret = rmi_f34v7_write_flash_config(f34); | ||
984 | if (ret < 0) | ||
985 | return ret; | ||
986 | |||
987 | f34->v7.config_area = v7_BL_CONFIG_AREA; | ||
988 | f34->v7.config_data = f34->v7.read_config_buf; | ||
989 | f34->v7.config_size = f34->v7.img.bl_config.size; | ||
990 | f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; | ||
991 | |||
992 | ret = rmi_f34v7_write_config(f34); | ||
993 | if (ret < 0) | ||
994 | return ret; | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | static int rmi_f34v7_write_firmware(struct f34_data *f34) | ||
1000 | { | ||
1001 | u16 blk_count; | ||
1002 | |||
1003 | blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size; | ||
1004 | |||
1005 | return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data, | ||
1006 | blk_count, v7_CMD_WRITE_FW); | ||
1007 | } | ||
1008 | |||
1009 | static void rmi_f34v7_compare_partition_tables(struct f34_data *f34) | ||
1010 | { | ||
1011 | if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) { | ||
1012 | f34->v7.new_partition_table = true; | ||
1013 | return; | ||
1014 | } | ||
1015 | |||
1016 | if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) { | ||
1017 | f34->v7.new_partition_table = true; | ||
1018 | return; | ||
1019 | } | ||
1020 | |||
1021 | if (f34->v7.has_display_cfg && | ||
1022 | f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) { | ||
1023 | f34->v7.new_partition_table = true; | ||
1024 | return; | ||
1025 | } | ||
1026 | |||
1027 | if (f34->v7.has_guest_code && | ||
1028 | f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) { | ||
1029 | f34->v7.new_partition_table = true; | ||
1030 | return; | ||
1031 | } | ||
1032 | |||
1033 | f34->v7.new_partition_table = false; | ||
1034 | } | ||
1035 | |||
1036 | static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34, | ||
1037 | const void *image) | ||
1038 | { | ||
1039 | int i; | ||
1040 | int num_of_containers; | ||
1041 | unsigned int addr; | ||
1042 | unsigned int container_id; | ||
1043 | unsigned int length; | ||
1044 | const void *content; | ||
1045 | const struct container_descriptor *descriptor; | ||
1046 | |||
1047 | num_of_containers = f34->v7.img.bootloader.size / 4 - 1; | ||
1048 | |||
1049 | for (i = 1; i <= num_of_containers; i++) { | ||
1050 | addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4); | ||
1051 | descriptor = image + addr; | ||
1052 | container_id = le16_to_cpu(descriptor->container_id); | ||
1053 | content = image + le32_to_cpu(descriptor->content_address); | ||
1054 | length = le32_to_cpu(descriptor->content_length); | ||
1055 | switch (container_id) { | ||
1056 | case BL_CONFIG_CONTAINER: | ||
1057 | case GLOBAL_PARAMETERS_CONTAINER: | ||
1058 | f34->v7.img.bl_config.data = content; | ||
1059 | f34->v7.img.bl_config.size = length; | ||
1060 | break; | ||
1061 | case BL_LOCKDOWN_INFO_CONTAINER: | ||
1062 | case DEVICE_CONFIG_CONTAINER: | ||
1063 | f34->v7.img.lockdown.data = content; | ||
1064 | f34->v7.img.lockdown.size = length; | ||
1065 | break; | ||
1066 | default: | ||
1067 | break; | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | static void rmi_f34v7_parse_image_header_10(struct f34_data *f34) | ||
1073 | { | ||
1074 | unsigned int i; | ||
1075 | unsigned int num_of_containers; | ||
1076 | unsigned int addr; | ||
1077 | unsigned int offset; | ||
1078 | unsigned int container_id; | ||
1079 | unsigned int length; | ||
1080 | const void *image = f34->v7.image; | ||
1081 | const u8 *content; | ||
1082 | const struct container_descriptor *descriptor; | ||
1083 | const struct image_header_10 *header = image; | ||
1084 | |||
1085 | f34->v7.img.checksum = le32_to_cpu(header->checksum); | ||
1086 | |||
1087 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n", | ||
1088 | __func__, f34->v7.img.checksum); | ||
1089 | |||
1090 | /* address of top level container */ | ||
1091 | offset = le32_to_cpu(header->top_level_container_start_addr); | ||
1092 | descriptor = image + offset; | ||
1093 | |||
1094 | /* address of top level container content */ | ||
1095 | offset = le32_to_cpu(descriptor->content_address); | ||
1096 | num_of_containers = le32_to_cpu(descriptor->content_length) / 4; | ||
1097 | |||
1098 | for (i = 0; i < num_of_containers; i++) { | ||
1099 | addr = get_unaligned_le32(image + offset); | ||
1100 | offset += 4; | ||
1101 | descriptor = image + addr; | ||
1102 | container_id = le16_to_cpu(descriptor->container_id); | ||
1103 | content = image + le32_to_cpu(descriptor->content_address); | ||
1104 | length = le32_to_cpu(descriptor->content_length); | ||
1105 | |||
1106 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
1107 | "%s: container_id=%d, length=%d\n", __func__, | ||
1108 | container_id, length); | ||
1109 | |||
1110 | switch (container_id) { | ||
1111 | case UI_CONTAINER: | ||
1112 | case CORE_CODE_CONTAINER: | ||
1113 | f34->v7.img.ui_firmware.data = content; | ||
1114 | f34->v7.img.ui_firmware.size = length; | ||
1115 | break; | ||
1116 | case UI_CONFIG_CONTAINER: | ||
1117 | case CORE_CONFIG_CONTAINER: | ||
1118 | f34->v7.img.ui_config.data = content; | ||
1119 | f34->v7.img.ui_config.size = length; | ||
1120 | break; | ||
1121 | case BL_CONTAINER: | ||
1122 | f34->v7.img.bl_version = *content; | ||
1123 | f34->v7.img.bootloader.data = content; | ||
1124 | f34->v7.img.bootloader.size = length; | ||
1125 | rmi_f34v7_parse_img_header_10_bl_container(f34, image); | ||
1126 | break; | ||
1127 | case GUEST_CODE_CONTAINER: | ||
1128 | f34->v7.img.contains_guest_code = true; | ||
1129 | f34->v7.img.guest_code.data = content; | ||
1130 | f34->v7.img.guest_code.size = length; | ||
1131 | break; | ||
1132 | case DISPLAY_CONFIG_CONTAINER: | ||
1133 | f34->v7.img.contains_display_cfg = true; | ||
1134 | f34->v7.img.dp_config.data = content; | ||
1135 | f34->v7.img.dp_config.size = length; | ||
1136 | break; | ||
1137 | case FLASH_CONFIG_CONTAINER: | ||
1138 | f34->v7.img.contains_flash_config = true; | ||
1139 | f34->v7.img.fl_config.data = content; | ||
1140 | f34->v7.img.fl_config.size = length; | ||
1141 | break; | ||
1142 | case GENERAL_INFORMATION_CONTAINER: | ||
1143 | f34->v7.img.contains_firmware_id = true; | ||
1144 | f34->v7.img.firmware_id = | ||
1145 | get_unaligned_le32(content + 4); | ||
1146 | break; | ||
1147 | default: | ||
1148 | break; | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | |||
1153 | static int rmi_f34v7_parse_image_info(struct f34_data *f34) | ||
1154 | { | ||
1155 | const struct image_header_10 *header = f34->v7.image; | ||
1156 | |||
1157 | memset(&f34->v7.img, 0x00, sizeof(f34->v7.img)); | ||
1158 | |||
1159 | rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, | ||
1160 | "%s: header->major_header_version = %d\n", | ||
1161 | __func__, header->major_header_version); | ||
1162 | |||
1163 | switch (header->major_header_version) { | ||
1164 | case IMAGE_HEADER_VERSION_10: | ||
1165 | rmi_f34v7_parse_image_header_10(f34); | ||
1166 | break; | ||
1167 | default: | ||
1168 | dev_err(&f34->fn->dev, "Unsupported image file format %02X\n", | ||
1169 | header->major_header_version); | ||
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | |||
1173 | if (!f34->v7.img.contains_flash_config) { | ||
1174 | dev_err(&f34->fn->dev, "%s: No flash config in fw image\n", | ||
1175 | __func__); | ||
1176 | return -EINVAL; | ||
1177 | } | ||
1178 | |||
1179 | rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data, | ||
1180 | &f34->v7.img.blkcount, &f34->v7.img.phyaddr); | ||
1181 | |||
1182 | rmi_f34v7_compare_partition_tables(f34); | ||
1183 | |||
1184 | return 0; | ||
1185 | } | ||
1186 | |||
1187 | int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw) | ||
1188 | { | ||
1189 | int ret; | ||
1190 | |||
1191 | rmi_f34v7_read_queries_bl_version(f34); | ||
1192 | |||
1193 | f34->v7.image = fw->data; | ||
1194 | |||
1195 | ret = rmi_f34v7_parse_image_info(f34); | ||
1196 | if (ret < 0) | ||
1197 | goto fail; | ||
1198 | |||
1199 | if (!f34->v7.new_partition_table) { | ||
1200 | ret = rmi_f34v7_check_ui_firmware_size(f34); | ||
1201 | if (ret < 0) | ||
1202 | goto fail; | ||
1203 | |||
1204 | ret = rmi_f34v7_check_ui_config_size(f34); | ||
1205 | if (ret < 0) | ||
1206 | goto fail; | ||
1207 | |||
1208 | if (f34->v7.has_display_cfg && | ||
1209 | f34->v7.img.contains_display_cfg) { | ||
1210 | ret = rmi_f34v7_check_dp_config_size(f34); | ||
1211 | if (ret < 0) | ||
1212 | goto fail; | ||
1213 | } | ||
1214 | |||
1215 | if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) { | ||
1216 | ret = rmi_f34v7_check_guest_code_size(f34); | ||
1217 | if (ret < 0) | ||
1218 | goto fail; | ||
1219 | } | ||
1220 | } else { | ||
1221 | ret = rmi_f34v7_check_bl_config_size(f34); | ||
1222 | if (ret < 0) | ||
1223 | goto fail; | ||
1224 | } | ||
1225 | |||
1226 | ret = rmi_f34v7_erase_all(f34); | ||
1227 | if (ret < 0) | ||
1228 | goto fail; | ||
1229 | |||
1230 | if (f34->v7.new_partition_table) { | ||
1231 | ret = rmi_f34v7_write_partition_table(f34); | ||
1232 | if (ret < 0) | ||
1233 | goto fail; | ||
1234 | dev_info(&f34->fn->dev, "%s: Partition table programmed\n", | ||
1235 | __func__); | ||
1236 | } | ||
1237 | |||
1238 | dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n", | ||
1239 | f34->v7.img.ui_firmware.size); | ||
1240 | |||
1241 | ret = rmi_f34v7_write_firmware(f34); | ||
1242 | if (ret < 0) | ||
1243 | goto fail; | ||
1244 | |||
1245 | dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n", | ||
1246 | f34->v7.img.ui_config.size); | ||
1247 | |||
1248 | f34->v7.config_area = v7_UI_CONFIG_AREA; | ||
1249 | ret = rmi_f34v7_write_ui_config(f34); | ||
1250 | if (ret < 0) | ||
1251 | goto fail; | ||
1252 | |||
1253 | if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) { | ||
1254 | dev_info(&f34->fn->dev, "Writing display config...\n"); | ||
1255 | |||
1256 | ret = rmi_f34v7_write_dp_config(f34); | ||
1257 | if (ret < 0) | ||
1258 | goto fail; | ||
1259 | } | ||
1260 | |||
1261 | if (f34->v7.new_partition_table) { | ||
1262 | if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) { | ||
1263 | dev_info(&f34->fn->dev, "Writing guest code...\n"); | ||
1264 | |||
1265 | ret = rmi_f34v7_write_guest_code(f34); | ||
1266 | if (ret < 0) | ||
1267 | goto fail; | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | fail: | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) | ||
1276 | { | ||
1277 | int ret; | ||
1278 | |||
1279 | ret = rmi_f34v7_read_flash_status(f34); | ||
1280 | if (ret < 0) | ||
1281 | return ret; | ||
1282 | |||
1283 | if (f34->v7.in_bl_mode) | ||
1284 | return 0; | ||
1285 | |||
1286 | ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG); | ||
1287 | if (ret < 0) | ||
1288 | return ret; | ||
1289 | |||
1290 | ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); | ||
1291 | if (ret < 0) | ||
1292 | return ret; | ||
1293 | |||
1294 | if (!f34->v7.in_bl_mode) { | ||
1295 | dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__); | ||
1296 | return -EINVAL; | ||
1297 | } | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw) | ||
1303 | { | ||
1304 | int ret = 0; | ||
1305 | |||
1306 | f34->v7.config_area = v7_UI_CONFIG_AREA; | ||
1307 | f34->v7.image = fw->data; | ||
1308 | |||
1309 | ret = rmi_f34v7_parse_image_info(f34); | ||
1310 | if (ret < 0) | ||
1311 | goto exit; | ||
1312 | |||
1313 | if (!f34->v7.force_update && f34->v7.new_partition_table) { | ||
1314 | dev_err(&f34->fn->dev, "%s: Partition table mismatch\n", | ||
1315 | __func__); | ||
1316 | ret = -EINVAL; | ||
1317 | goto exit; | ||
1318 | } | ||
1319 | |||
1320 | dev_info(&f34->fn->dev, "Firmware image OK\n"); | ||
1321 | |||
1322 | ret = rmi_f34v7_read_flash_status(f34); | ||
1323 | if (ret < 0) | ||
1324 | goto exit; | ||
1325 | |||
1326 | if (f34->v7.in_bl_mode) { | ||
1327 | dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n", | ||
1328 | __func__); | ||
1329 | } | ||
1330 | |||
1331 | rmi_f34v7_enter_flash_prog(f34); | ||
1332 | |||
1333 | return 0; | ||
1334 | |||
1335 | exit: | ||
1336 | return ret; | ||
1337 | } | ||
1338 | |||
1339 | int rmi_f34v7_probe(struct f34_data *f34) | ||
1340 | { | ||
1341 | int ret; | ||
1342 | |||
1343 | /* Read bootloader version */ | ||
1344 | ret = rmi_read_block(f34->fn->rmi_dev, | ||
1345 | f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET, | ||
1346 | f34->bootloader_id, | ||
1347 | sizeof(f34->bootloader_id)); | ||
1348 | if (ret < 0) { | ||
1349 | dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n", | ||
1350 | __func__); | ||
1351 | return ret; | ||
1352 | } | ||
1353 | |||
1354 | if (f34->bootloader_id[1] == '5') { | ||
1355 | f34->bl_version = 5; | ||
1356 | } else if (f34->bootloader_id[1] == '6') { | ||
1357 | f34->bl_version = 6; | ||
1358 | } else if (f34->bootloader_id[1] == 7) { | ||
1359 | f34->bl_version = 7; | ||
1360 | } else { | ||
1361 | dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n", | ||
1362 | __func__); | ||
1363 | return -EINVAL; | ||
1364 | } | ||
1365 | |||
1366 | memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount)); | ||
1367 | memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr)); | ||
1368 | rmi_f34v7_read_queries(f34); | ||
1369 | |||
1370 | f34->v7.force_update = false; | ||
1371 | return 0; | ||
1372 | } | ||
diff --git a/include/linux/rmi.h b/include/linux/rmi.h index ac910f730688..64125443f8a6 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h | |||
@@ -342,7 +342,7 @@ struct rmi_driver_data { | |||
342 | 342 | ||
343 | struct rmi_function *f01_container; | 343 | struct rmi_function *f01_container; |
344 | struct rmi_function *f34_container; | 344 | struct rmi_function *f34_container; |
345 | bool f01_bootloader_mode; | 345 | bool bootloader_mode; |
346 | 346 | ||
347 | int num_of_irq_regs; | 347 | int num_of_irq_regs; |
348 | int irq_count; | 348 | int irq_count; |