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