1 /*
2 * cyttsp5_loader.c
3 * Parade TrueTouch(TM) Standard Product V5 FW Loader Module.
4 * For use with Parade touchscreen controllers.
5 * Supported parts include:
6 * CYTMA5XX
7 * CYTMA448
8 * CYTMA445A
9 * CYTT21XXX
10 * CYTT31XXX
11 *
12 * Copyright (C) 2015 Parade Technologies
13 * Copyright (C) 2012-2015 Cypress Semiconductor, Inc.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * version 2, and only version 2, as published by the
18 * Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
26 *
27 */
28
29 #include "cyttsp5_regs.h"
30 #include <linux/firmware.h>
31
32 #define CYTTSP5_LOADER_NAME "cyttsp5_loader"
33 #define CY_FW_MANUAL_UPGRADE_FILE_NAME "cyttsp5_fw_manual_upgrade"
34
35 /* Enable UPGRADE_FW_AND_CONFIG_IN_PROBE definition
36 * to perform FW and config upgrade during probe
37 * instead of scheduling a work for it
38 */
39 /* #define UPGRADE_FW_AND_CONFIG_IN_PROBE */
40
41 #define CYTTSP5_AUTO_LOAD_FOR_CORRUPTED_FW 1
42 #define CYTTSP5_LOADER_FW_UPGRADE_RETRY_COUNT 3
43
44
45 #if defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE) || defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE)
46 #define CYTTSP5_FW_UPGRADE 1
47 #else
48 #define CYTTSP5_FW_UPGRADE 0
49 #endif
50
51 #if defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE) || defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE)
52 #define CYTTSP5_TTCONFIG_UPGRADE 1
53 #else
54 #define CYTTSP5_TTCONFIG_UPGRADE 0
55 #endif
56
57 static const u8 cyttsp5_security_key[] = {
58 0xA5, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD, 0x5A
59 };
60
61 /* Timeout values in ms. */
62 #define CY_LDR_REQUEST_EXCLUSIVE_TIMEOUT 500
63 #define CY_LDR_SWITCH_TO_APP_MODE_TIMEOUT 300
64
65 #define CY_MAX_STATUS_SIZE 32
66
67 #define CY_DATA_MAX_ROW_SIZE 256
68 #define CY_DATA_ROW_SIZE 128
69
70 #define CY_ARRAY_ID_OFFSET 0
71 #define CY_ROW_NUM_OFFSET 1
72 #define CY_ROW_SIZE_OFFSET 3
73 #define CY_ROW_DATA_OFFSET 5
74
75 #define CY_POST_TT_CFG_CRC_MASK 0x2
76
77 struct cyttsp5_loader_data {
78 struct device *dev;
79 struct cyttsp5_sysinfo *si;
80 u8 status_buf[CY_MAX_STATUS_SIZE];
81 struct completion int_running;
82 struct completion calibration_complete;
83 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
84 struct completion builtin_bin_fw_complete;
85 int builtin_bin_fw_status;
86 bool is_manual_upgrade_enabled;
87 #endif
88 struct work_struct fw_and_config_upgrade;
89 struct work_struct calibration_work;
90 struct cyttsp5_loader_platform_data *loader_pdata;
91 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
92 struct mutex config_lock;
93 u8 *config_data;
94 int config_size;
95 bool config_loading;
96 #endif
97 };
98
99 struct cyttsp5_dev_id {
100 u32 silicon_id;
101 u8 rev_id;
102 u32 bl_ver;
103 };
104
105 struct cyttsp5_hex_image {
106 u8 array_id;
107 u16 row_num;
108 u16 row_size;
109 u8 row_data[CY_DATA_ROW_SIZE];
110 } __packed;
111
112 static struct cyttsp5_core_commands *cmd;
113
114 static struct cyttsp5_module loader_module;
115
cyttsp5_get_loader_data(struct device * dev)116 static inline struct cyttsp5_loader_data *cyttsp5_get_loader_data(
117 struct device *dev)
118 {
119 return cyttsp5_get_module_data(dev, &loader_module);
120 }
121
122 #if CYTTSP5_FW_UPGRADE \
123 || defined(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE)
cyttsp5_get_panel_id(struct device * dev)124 static u8 cyttsp5_get_panel_id(struct device *dev)
125 {
126 struct cyttsp5_core_data *cd = dev_get_drvdata(dev);
127
128 return cd->panel_id;
129 }
130 #endif
131
132 #if CYTTSP5_FW_UPGRADE || CYTTSP5_TTCONFIG_UPGRADE
133 /*
134 * return code:
135 * -1: Do not upgrade firmware
136 * 0: Version info same, let caller decide
137 * 1: Do a firmware upgrade
138 */
cyttsp5_check_firmware_version(struct device * dev,u32 fw_ver_new,u32 fw_revctrl_new)139 static int cyttsp5_check_firmware_version(struct device *dev,
140 u32 fw_ver_new, u32 fw_revctrl_new)
141 {
142 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
143 u32 fw_ver_img;
144 u32 fw_revctrl_img;
145
146 fw_ver_img = ld->si->cydata.fw_ver_major << 8;
147 fw_ver_img += ld->si->cydata.fw_ver_minor;
148
149 parade_debug(dev, DEBUG_LEVEL_1,
150 "%s: img vers:0x%04X new vers:0x%04X\n", __func__,
151 fw_ver_img, fw_ver_new);
152
153 if (fw_ver_new > fw_ver_img) {
154 parade_debug(dev, DEBUG_LEVEL_1,
155 "%s: Image is newer, will upgrade\n", __func__);
156 return 1;
157 }
158
159 if (fw_ver_new < fw_ver_img) {
160 parade_debug(dev, DEBUG_LEVEL_1,
161 "%s: Image is older, will NOT upgrade\n", __func__);
162 return -1;
163 }
164
165 fw_revctrl_img = ld->si->cydata.revctrl;
166
167 parade_debug(dev, DEBUG_LEVEL_1,
168 "%s: img revctrl:0x%04X new revctrl:0x%04X\n",
169 __func__, fw_revctrl_img, fw_revctrl_new);
170
171 if (fw_revctrl_new > fw_revctrl_img) {
172 parade_debug(dev, DEBUG_LEVEL_1,
173 "%s: Image is newer, will upgrade\n", __func__);
174 return 1;
175 }
176
177 if (fw_revctrl_new < fw_revctrl_img) {
178 parade_debug(dev, DEBUG_LEVEL_1,
179 "%s: Image is older, will NOT upgrade\n", __func__);
180 return -1;
181 }
182
183 return 0;
184 }
185
cyttsp5_calibrate_idacs(struct work_struct * calibration_work)186 static void cyttsp5_calibrate_idacs(struct work_struct *calibration_work)
187 {
188 struct cyttsp5_loader_data *ld = container_of(calibration_work,
189 struct cyttsp5_loader_data, calibration_work);
190 struct device *dev = ld->dev;
191 u8 mode;
192 u8 status;
193 int rc;
194
195 rc = cmd->request_exclusive(dev, CY_LDR_REQUEST_EXCLUSIVE_TIMEOUT);
196 if (rc < 0)
197 goto exit;
198
199 rc = cmd->nonhid_cmd->suspend_scanning(dev, 0);
200 if (rc < 0)
201 goto release;
202
203 for (mode = 0; mode < 3; mode++) {
204 rc = cmd->nonhid_cmd->calibrate_idacs(dev, 0, mode, &status);
205 if (rc < 0)
206 goto release;
207 }
208
209 rc = cmd->nonhid_cmd->resume_scanning(dev, 0);
210 if (rc < 0)
211 goto release;
212
213 parade_debug(dev, DEBUG_LEVEL_1, "%s: Calibration Done\n", __func__);
214
215 release:
216 cmd->release_exclusive(dev);
217 exit:
218 complete(&ld->calibration_complete);
219 }
220
cyttsp5_calibration_attention(struct device * dev)221 static int cyttsp5_calibration_attention(struct device *dev)
222 {
223 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
224 int rc = 0;
225
226 schedule_work(&ld->calibration_work);
227
228 cmd->unsubscribe_attention(dev, CY_ATTEN_STARTUP, CYTTSP5_LOADER_NAME,
229 cyttsp5_calibration_attention, 0);
230
231 return rc;
232 }
233
234
235 #endif /* CYTTSP5_FW_UPGRADE || CYTTSP5_TTCONFIG_UPGRADE */
236
237 #if CYTTSP5_FW_UPGRADE
cyttsp5_get_row_(struct device * dev,u8 * row_buf,u8 * image_buf,int size)238 static u8 *cyttsp5_get_row_(struct device *dev, u8 *row_buf,
239 u8 *image_buf, int size)
240 {
241 memcpy(row_buf, image_buf, size);
242 return image_buf + size;
243 }
244
cyttsp5_ldr_enter_(struct device * dev,struct cyttsp5_dev_id * dev_id)245 static int cyttsp5_ldr_enter_(struct device *dev, struct cyttsp5_dev_id *dev_id)
246 {
247 int rc;
248 u8 return_data[8];
249 u8 mode;
250
251 dev_id->silicon_id = 0;
252 dev_id->rev_id = 0;
253 dev_id->bl_ver = 0;
254
255 cmd->request_reset(dev);
256
257 rc = cmd->request_get_mode(dev, 0, &mode);
258 if (rc < 0)
259 return rc;
260
261 if (mode == CY_MODE_UNKNOWN)
262 return -EINVAL;
263
264 if (mode == CY_MODE_OPERATIONAL) {
265 rc = cmd->nonhid_cmd->start_bl(dev, 0);
266 if (rc < 0)
267 return rc;
268 }
269
270 rc = cmd->nonhid_cmd->get_bl_info(dev, 0, return_data);
271 if (rc < 0)
272 return rc;
273
274 dev_id->silicon_id = get_unaligned_le32(&return_data[0]);
275 dev_id->rev_id = return_data[4];
276 dev_id->bl_ver = return_data[5] + (return_data[6] << 8)
277 + (return_data[7] << 16);
278
279 return 0;
280 }
281
cyttsp5_ldr_init_(struct device * dev,struct cyttsp5_hex_image * row_image)282 static int cyttsp5_ldr_init_(struct device *dev,
283 struct cyttsp5_hex_image *row_image)
284 {
285 return cmd->nonhid_cmd->initiate_bl(dev, 0, 8,
286 (u8 *)cyttsp5_security_key, row_image->row_size,
287 row_image->row_data);
288 }
289
cyttsp5_ldr_parse_row_(struct device * dev,u8 * row_buf,struct cyttsp5_hex_image * row_image)290 static int cyttsp5_ldr_parse_row_(struct device *dev, u8 *row_buf,
291 struct cyttsp5_hex_image *row_image)
292 {
293 int rc = 0;
294
295 row_image->array_id = row_buf[CY_ARRAY_ID_OFFSET];
296 row_image->row_num = get_unaligned_be16(&row_buf[CY_ROW_NUM_OFFSET]);
297 row_image->row_size = get_unaligned_be16(&row_buf[CY_ROW_SIZE_OFFSET]);
298
299 if (row_image->row_size > ARRAY_SIZE(row_image->row_data)) {
300 dev_err(dev, "%s: row data buffer overflow\n", __func__);
301 rc = -EOVERFLOW;
302 goto cyttsp5_ldr_parse_row_exit;
303 }
304
305 memcpy(row_image->row_data, &row_buf[CY_ROW_DATA_OFFSET],
306 row_image->row_size);
307 cyttsp5_ldr_parse_row_exit:
308 return rc;
309 }
310
cyttsp5_ldr_prog_row_(struct device * dev,struct cyttsp5_hex_image * row_image)311 static int cyttsp5_ldr_prog_row_(struct device *dev,
312 struct cyttsp5_hex_image *row_image)
313 {
314 u16 length = row_image->row_size + 3;
315 u8 data[3 + row_image->row_size];
316 u8 offset = 0;
317
318 data[offset++] = row_image->array_id;
319 data[offset++] = LOW_BYTE(row_image->row_num);
320 data[offset++] = HI_BYTE(row_image->row_num);
321 memcpy(data + 3, row_image->row_data, row_image->row_size);
322 return cmd->nonhid_cmd->prog_and_verify(dev, 0, length, data);
323 }
324
cyttsp5_ldr_verify_chksum_(struct device * dev)325 static int cyttsp5_ldr_verify_chksum_(struct device *dev)
326 {
327 u8 result;
328 int rc;
329
330 rc = cmd->nonhid_cmd->verify_app_integrity(dev, 0, &result);
331 if (rc)
332 return rc;
333
334 /* fail */
335 if (result == 0)
336 return -EINVAL;
337
338 return 0;
339 }
340
cyttsp5_ldr_exit_(struct device * dev)341 static int cyttsp5_ldr_exit_(struct device *dev)
342 {
343 return cmd->nonhid_cmd->launch_app(dev, 0);
344 }
345
cyttsp5_load_app_(struct device * dev,const u8 * fw,int fw_size)346 static int cyttsp5_load_app_(struct device *dev, const u8 *fw, int fw_size)
347 {
348 struct cyttsp5_dev_id *dev_id;
349 struct cyttsp5_hex_image *row_image;
350 u8 *row_buf;
351 size_t image_rec_size;
352 size_t row_buf_size = CY_DATA_MAX_ROW_SIZE;
353 int row_count = 0;
354 u8 *p;
355 u8 *last_row;
356 int rc;
357 int rc_tmp;
358
359 image_rec_size = sizeof(struct cyttsp5_hex_image);
360 if (fw_size % image_rec_size != 0) {
361 dev_err(dev, "%s: Firmware image is misaligned\n", __func__);
362 rc = -EINVAL;
363 goto _cyttsp5_load_app_error;
364 }
365
366 dev_info(dev, "%s: start load app\n", __func__);
367 #ifdef TTHE_TUNER_SUPPORT
368 cmd->request_tthe_print(dev, NULL, 0, "start load app");
369 #endif
370
371 row_buf = kzalloc(row_buf_size, GFP_KERNEL);
372 row_image = kzalloc(sizeof(struct cyttsp5_hex_image), GFP_KERNEL);
373 dev_id = kzalloc(sizeof(struct cyttsp5_dev_id), GFP_KERNEL);
374 if (!row_buf || !row_image || !dev_id) {
375 rc = -ENOMEM;
376 goto _cyttsp5_load_app_exit;
377 }
378
379 cmd->request_stop_wd(dev);
380
381 dev_info(dev, "%s: Send BL Loader Enter\n", __func__);
382 #ifdef TTHE_TUNER_SUPPORT
383 cmd->request_tthe_print(dev, NULL, 0, "Send BL Loader Enter");
384 #endif
385 rc = cyttsp5_ldr_enter_(dev, dev_id);
386 if (rc) {
387 dev_err(dev, "%s: Error cannot start Loader (ret=%d)\n",
388 __func__, rc);
389 goto _cyttsp5_load_app_exit;
390 }
391 parade_debug(dev, DEBUG_LEVEL_2, "%s: dev: silicon id=%08X rev=%02X bl=%08X\n",
392 __func__, dev_id->silicon_id,
393 dev_id->rev_id, dev_id->bl_ver);
394
395 /* get last row */
396 last_row = (u8 *)fw + fw_size - image_rec_size;
397 cyttsp5_get_row_(dev, row_buf, last_row, image_rec_size);
398 cyttsp5_ldr_parse_row_(dev, row_buf, row_image);
399
400 /* initialise bootloader */
401 rc = cyttsp5_ldr_init_(dev, row_image);
402 if (rc) {
403 dev_err(dev, "%s: Error cannot init Loader (ret=%d)\n",
404 __func__, rc);
405 goto _cyttsp5_load_app_exit;
406 }
407
408 dev_info(dev, "%s: Send BL Loader Blocks\n", __func__);
409 #ifdef TTHE_TUNER_SUPPORT
410 cmd->request_tthe_print(dev, NULL, 0, "Send BL Loader Blocks");
411 #endif
412 p = (u8 *)fw;
413 while (p < last_row) {
414 /* Get row */
415 parade_debug(dev, DEBUG_LEVEL_1, "%s: read row=%d\n",
416 __func__, ++row_count);
417 memset(row_buf, 0, row_buf_size);
418 p = cyttsp5_get_row_(dev, row_buf, p, image_rec_size);
419
420 /* Parse row */
421 parade_debug(dev, DEBUG_LEVEL_2, "%s: p=%p buf=%p buf[0]=%02X\n",
422 __func__, p, row_buf, row_buf[0]);
423 rc = cyttsp5_ldr_parse_row_(dev, row_buf, row_image);
424 parade_debug(dev, DEBUG_LEVEL_2, "%s: array_id=%02X row_num=%04X(%d) row_size=%04X(%d)\n",
425 __func__, row_image->array_id,
426 row_image->row_num, row_image->row_num,
427 row_image->row_size, row_image->row_size);
428 if (rc) {
429 dev_err(dev, "%s: Parse Row Error (a=%d r=%d ret=%d\n",
430 __func__, row_image->array_id,
431 row_image->row_num, rc);
432 goto _cyttsp5_load_app_exit;
433 } else {
434 parade_debug(dev, DEBUG_LEVEL_2, "%s: Parse Row (a=%d r=%d ret=%d\n",
435 __func__, row_image->array_id,
436 row_image->row_num, rc);
437 }
438
439 /* program row */
440 rc = cyttsp5_ldr_prog_row_(dev, row_image);
441 if (rc) {
442 dev_err(dev, "%s: Program Row Error (array=%d row=%d ret=%d)\n",
443 __func__, row_image->array_id,
444 row_image->row_num, rc);
445 goto _cyttsp5_load_app_exit;
446 }
447
448 parade_debug(dev, DEBUG_LEVEL_2, "%s: array=%d row_cnt=%d row_num=%04X\n",
449 __func__, row_image->array_id, row_count,
450 row_image->row_num);
451 }
452
453 /* exit loader */
454 dev_info(dev, "%s: Send BL Loader Terminate\n", __func__);
455 #ifdef TTHE_TUNER_SUPPORT
456 cmd->request_tthe_print(dev, NULL, 0, "Send BL Loader Terminate");
457 #endif
458 rc = cyttsp5_ldr_exit_(dev);
459 if (rc) {
460 dev_err(dev, "%s: Error on exit Loader (ret=%d)\n",
461 __func__, rc);
462
463 /* verify app checksum */
464 rc_tmp = cyttsp5_ldr_verify_chksum_(dev);
465 if (rc_tmp)
466 dev_err(dev, "%s: ldr_verify_chksum fail r=%d\n",
467 __func__, rc_tmp);
468 else
469 dev_info(dev, "%s: APP Checksum Verified\n", __func__);
470 }
471
472 _cyttsp5_load_app_exit:
473 kfree(row_buf);
474 kfree(row_image);
475 kfree(dev_id);
476 _cyttsp5_load_app_error:
477 return rc;
478 }
479
cyttsp5_upgrade_firmware(struct device * dev,const u8 * fw_img,int fw_size)480 static int cyttsp5_upgrade_firmware(struct device *dev, const u8 *fw_img,
481 int fw_size)
482 {
483 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
484 int retry = CYTTSP5_LOADER_FW_UPGRADE_RETRY_COUNT;
485 bool wait_for_calibration_complete = false;
486 int rc;
487
488 pm_runtime_get_sync(dev);
489
490 rc = cmd->request_exclusive(dev, CY_LDR_REQUEST_EXCLUSIVE_TIMEOUT);
491 if (rc < 0)
492 goto exit;
493
494 while (retry--) {
495 rc = cyttsp5_load_app_(dev, fw_img, fw_size);
496 if (rc < 0)
497 dev_err(dev, "%s: Firmware update failed rc=%d, retry:%d\n",
498 __func__, rc, retry);
499 else
500 break;
501 msleep(20);
502 }
503 if (rc < 0) {
504 dev_err(dev, "%s: Firmware update failed with error code %d\n",
505 __func__, rc);
506 } else if (ld->loader_pdata &&
507 (ld->loader_pdata->flags
508 & CY_LOADER_FLAG_CALIBRATE_AFTER_FW_UPGRADE)) {
509 #if (KERNEL_VERSION(3, 13, 0) <= LINUX_VERSION_CODE)
510 reinit_completion(&ld->calibration_complete);
511 #else
512 INIT_COMPLETION(ld->calibration_complete);
513 #endif
514 /* set up call back for startup */
515 parade_debug(dev, DEBUG_LEVEL_2, "%s: Adding callback for calibration\n",
516 __func__);
517 rc = cmd->subscribe_attention(dev, CY_ATTEN_STARTUP,
518 CYTTSP5_LOADER_NAME, cyttsp5_calibration_attention, 0);
519 if (rc) {
520 dev_err(dev, "%s: Failed adding callback for calibration\n",
521 __func__);
522 dev_err(dev, "%s: No calibration will be performed\n",
523 __func__);
524 rc = 0;
525 } else
526 wait_for_calibration_complete = true;
527 }
528
529 cmd->release_exclusive(dev);
530
531 exit:
532 if (!rc)
533 cmd->request_restart(dev, true);
534
535 pm_runtime_put_sync(dev);
536
537 if (wait_for_calibration_complete)
538 wait_for_completion(&ld->calibration_complete);
539
540 return rc;
541 }
542
cyttsp5_loader_attention(struct device * dev)543 static int cyttsp5_loader_attention(struct device *dev)
544 {
545 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
546
547 complete(&ld->int_running);
548 return 0;
549 }
550 #endif /* CYTTSP5_FW_UPGRADE */
551
552 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
cyttsp5_check_firmware_version_platform(struct device * dev,struct cyttsp5_touch_firmware * fw)553 static int cyttsp5_check_firmware_version_platform(struct device *dev,
554 struct cyttsp5_touch_firmware *fw)
555 {
556 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
557 u32 fw_ver_new;
558 u32 fw_revctrl_new;
559 int upgrade;
560
561 if (!ld->si) {
562 dev_info(dev, "%s: No firmware infomation found, device FW may be corrupted\n",
563 __func__);
564 return CYTTSP5_AUTO_LOAD_FOR_CORRUPTED_FW;
565 }
566
567 fw_ver_new = get_unaligned_be16(fw->ver + 2);
568 /* 4 middle bytes are not used */
569 fw_revctrl_new = get_unaligned_be32(fw->ver + 8);
570
571 upgrade = cyttsp5_check_firmware_version(dev, fw_ver_new,
572 fw_revctrl_new);
573
574 if (upgrade > 0)
575 return 1;
576
577 return 0;
578 }
579
cyttsp5_get_platform_firmware(struct device * dev)580 static struct cyttsp5_touch_firmware *cyttsp5_get_platform_firmware(
581 struct device *dev)
582 {
583 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
584 struct cyttsp5_touch_firmware **fws;
585 struct cyttsp5_touch_firmware *fw;
586 u8 panel_id;
587
588 panel_id = cyttsp5_get_panel_id(dev);
589 if (panel_id == PANEL_ID_NOT_ENABLED) {
590 parade_debug(dev, DEBUG_LEVEL_1, "%s: Panel ID not enabled, using legacy firmware\n",
591 __func__);
592 return ld->loader_pdata->fw;
593 }
594
595 fws = ld->loader_pdata->fws;
596 if (!fws) {
597 dev_err(dev, "%s: No firmwares provided\n", __func__);
598 return NULL;
599 }
600
601 /* Find FW according to the Panel ID */
602 while ((fw = *fws++)) {
603 if (fw->panel_id == panel_id) {
604 parade_debug(dev, DEBUG_LEVEL_1, "%s: Found matching fw:%p with Panel ID: 0x%02X\n",
605 __func__, fw, fw->panel_id);
606 return fw;
607 }
608 parade_debug(dev, DEBUG_LEVEL_2, "%s: Found mismatching fw:%p with Panel ID: 0x%02X\n",
609 __func__, fw, fw->panel_id);
610 }
611
612 return NULL;
613 }
614
upgrade_firmware_from_platform(struct device * dev,bool forced)615 static int upgrade_firmware_from_platform(struct device *dev,
616 bool forced)
617 {
618 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
619 struct cyttsp5_touch_firmware *fw;
620 int rc = -ENODEV;
621 int upgrade;
622
623 if (!ld->loader_pdata) {
624 dev_err(dev, "%s: No loader platform data\n", __func__);
625 return rc;
626 }
627
628 fw = cyttsp5_get_platform_firmware(dev);
629 if (!fw || !fw->img || !fw->size) {
630 dev_err(dev, "%s: No platform firmware\n", __func__);
631 return rc;
632 }
633
634 if (!fw->ver || !fw->vsize) {
635 dev_err(dev, "%s: No platform firmware version\n",
636 __func__);
637 return rc;
638 }
639
640 if (forced)
641 upgrade = forced;
642 else
643 upgrade = cyttsp5_check_firmware_version_platform(dev, fw);
644
645 if (upgrade)
646 return cyttsp5_upgrade_firmware(dev, fw->img, fw->size);
647
648 return rc;
649 }
650 #endif /* CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE */
651
652 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
_cyttsp5_firmware_cont(const struct firmware * fw,void * context)653 static void _cyttsp5_firmware_cont(const struct firmware *fw, void *context)
654 {
655 struct device *dev = context;
656 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
657 u8 header_size = 0;
658
659 if (!fw)
660 goto cyttsp5_firmware_cont_exit;
661
662 if (!fw->data || !fw->size) {
663 dev_err(dev, "%s: No firmware received\n", __func__);
664 goto cyttsp5_firmware_cont_release_exit;
665 }
666
667 header_size = fw->data[0];
668 if (header_size >= (fw->size + 1)) {
669 dev_err(dev, "%s: Firmware format is invalid\n", __func__);
670 goto cyttsp5_firmware_cont_release_exit;
671 }
672
673 cyttsp5_upgrade_firmware(dev, &(fw->data[header_size + 1]),
674 fw->size - (header_size + 1));
675
676 cyttsp5_firmware_cont_release_exit:
677 release_firmware(fw);
678
679 cyttsp5_firmware_cont_exit:
680 ld->is_manual_upgrade_enabled = 0;
681 }
682
cyttsp5_check_firmware_version_builtin(struct device * dev,const struct firmware * fw)683 static int cyttsp5_check_firmware_version_builtin(struct device *dev,
684 const struct firmware *fw)
685 {
686 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
687 u32 fw_ver_new;
688 u32 fw_revctrl_new;
689 int upgrade;
690
691 if (!ld->si) {
692 dev_info(dev, "%s: No firmware infomation found, device FW may be corrupted\n",
693 __func__);
694 return CYTTSP5_AUTO_LOAD_FOR_CORRUPTED_FW;
695 }
696
697 fw_ver_new = get_unaligned_be16(fw->data + 3);
698 /* 4 middle bytes are not used */
699 fw_revctrl_new = get_unaligned_be32(fw->data + 9);
700
701 upgrade = cyttsp5_check_firmware_version(dev, fw_ver_new,
702 fw_revctrl_new);
703
704 if (upgrade > 0)
705 return 1;
706
707 return 0;
708 }
709
_cyttsp5_firmware_cont_builtin(const struct firmware * fw,void * context)710 static void _cyttsp5_firmware_cont_builtin(const struct firmware *fw,
711 void *context)
712 {
713 struct device *dev = context;
714 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
715 int upgrade;
716
717 if (!fw) {
718 dev_info(dev, "%s: No builtin firmware\n", __func__);
719 goto _cyttsp5_firmware_cont_builtin_exit;
720 }
721
722 if (!fw->data || !fw->size) {
723 dev_err(dev, "%s: Invalid builtin firmware\n", __func__);
724 goto _cyttsp5_firmware_cont_builtin_exit;
725 }
726
727 parade_debug(dev, DEBUG_LEVEL_1, "%s: Found firmware\n", __func__);
728
729 upgrade = cyttsp5_check_firmware_version_builtin(dev, fw);
730 if (upgrade) {
731 _cyttsp5_firmware_cont(fw, dev);
732 ld->builtin_bin_fw_status = 0;
733 complete(&ld->builtin_bin_fw_complete);
734 return;
735 }
736
737 _cyttsp5_firmware_cont_builtin_exit:
738 release_firmware(fw);
739
740 ld->builtin_bin_fw_status = -EINVAL;
741 complete(&ld->builtin_bin_fw_complete);
742 }
743
upgrade_firmware_from_class(struct device * dev)744 static int upgrade_firmware_from_class(struct device *dev)
745 {
746 int retval;
747
748 parade_debug(dev, DEBUG_LEVEL_2,
749 "%s: Enabling firmware class loader\n", __func__);
750
751 retval = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
752 CY_FW_MANUAL_UPGRADE_FILE_NAME, dev, GFP_KERNEL, dev,
753 _cyttsp5_firmware_cont);
754 if (retval < 0) {
755 dev_err(dev, "%s: Fail request firmware class file load\n",
756 __func__);
757 return retval;
758 }
759
760 return 0;
761 }
762
763 /*
764 * Generates binary FW filename as following:
765 * - Panel ID not enabled: cyttsp5_fw.bin
766 * - Panel ID enabled: cyttsp5_fw_pidXX.bin
767 */
generate_firmware_filename(struct device * dev)768 static char *generate_firmware_filename(struct device *dev)
769 {
770 char *filename;
771 u8 panel_id;
772
773 #define FILENAME_LEN_MAX 64
774 filename = kzalloc(FILENAME_LEN_MAX, GFP_KERNEL);
775 if (!filename)
776 return NULL;
777
778 panel_id = cyttsp5_get_panel_id(dev);
779 if (panel_id == PANEL_ID_NOT_ENABLED)
780 snprintf(filename, FILENAME_LEN_MAX, "%s", CY_FW_FILE_NAME);
781 else
782 snprintf(filename, FILENAME_LEN_MAX, "%s_pid%02X%s",
783 CY_FW_FILE_PREFIX, panel_id, CY_FW_FILE_SUFFIX);
784
785 parade_debug(dev, DEBUG_LEVEL_1, "%s: Filename: %s\n",
786 __func__, filename);
787
788 return filename;
789 }
790
upgrade_firmware_from_builtin(struct device * dev)791 static int upgrade_firmware_from_builtin(struct device *dev)
792 {
793 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
794 char *filename;
795 int retval;
796
797 parade_debug(dev, DEBUG_LEVEL_2,
798 "%s: Enabling firmware class loader built-in\n",
799 __func__);
800
801 filename = generate_firmware_filename(dev);
802 if (!filename)
803 return -ENOMEM;
804
805 retval = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
806 filename, dev, GFP_KERNEL, dev,
807 _cyttsp5_firmware_cont_builtin);
808 if (retval < 0) {
809 dev_err(dev, "%s: Fail request firmware class file load\n",
810 __func__);
811 goto exit;
812 }
813
814 /* wait until FW binary upgrade finishes */
815 wait_for_completion(&ld->builtin_bin_fw_complete);
816
817 retval = ld->builtin_bin_fw_status;
818
819 exit:
820 kfree(filename);
821
822 return retval;
823 }
824 #endif /* CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE */
825
826 #if CYTTSP5_TTCONFIG_UPGRADE
cyttsp5_write_config_row_(struct device * dev,u8 ebid,u16 row_number,u16 row_size,u8 * data)827 static int cyttsp5_write_config_row_(struct device *dev, u8 ebid,
828 u16 row_number, u16 row_size, u8 *data)
829 {
830 int rc;
831 u16 actual_write_len;
832
833 rc = cmd->nonhid_cmd->write_conf_block(dev, 0, row_number,
834 row_size, ebid, data, (u8 *)cyttsp5_security_key,
835 &actual_write_len);
836 if (rc) {
837 dev_err(dev, "%s: Fail Put EBID=%d row=%d cmd fail r=%d\n",
838 __func__, ebid, row_number, rc);
839 return rc;
840 }
841
842 if (actual_write_len != row_size) {
843 dev_err(dev, "%s: Fail Put EBID=%d row=%d wrong write size=%d\n",
844 __func__, ebid, row_number, actual_write_len);
845 rc = -EINVAL;
846 }
847
848 return rc;
849 }
850
cyttsp5_upgrade_ttconfig(struct device * dev,const u8 * ttconfig_data,int ttconfig_size)851 static int cyttsp5_upgrade_ttconfig(struct device *dev,
852 const u8 *ttconfig_data, int ttconfig_size)
853 {
854 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
855 bool wait_for_calibration_complete = false;
856 u8 ebid = CY_TCH_PARM_EBID;
857 u16 row_size = CY_DATA_ROW_SIZE;
858 u16 table_size;
859 u16 row_count;
860 u16 residue;
861 u8 *row_buf;
862 u8 verify_crc_status;
863 u16 calculated_crc;
864 u16 stored_crc;
865 int rc = 0;
866 int i;
867
868 table_size = ttconfig_size;
869 row_count = table_size / row_size;
870 row_buf = (u8 *)ttconfig_data;
871 parade_debug(dev, DEBUG_LEVEL_1, "%s: size:%d row_size=%d row_count=%d\n",
872 __func__, table_size, row_size, row_count);
873
874 pm_runtime_get_sync(dev);
875
876 rc = cmd->request_exclusive(dev, CY_LDR_REQUEST_EXCLUSIVE_TIMEOUT);
877 if (rc < 0)
878 goto exit;
879
880 rc = cmd->nonhid_cmd->suspend_scanning(dev, 0);
881 if (rc < 0)
882 goto release;
883
884 for (i = 0; i < row_count; i++) {
885 parade_debug(dev, DEBUG_LEVEL_1, "%s: row=%d size=%d\n",
886 __func__, i, row_size);
887 rc = cyttsp5_write_config_row_(dev, ebid, i, row_size,
888 row_buf);
889 if (rc) {
890 dev_err(dev, "%s: Fail put row=%d r=%d\n",
891 __func__, i, rc);
892 break;
893 }
894 row_buf += row_size;
895 }
896 if (!rc) {
897 residue = table_size % row_size;
898 parade_debug(dev, DEBUG_LEVEL_1, "%s: row=%d size=%d\n",
899 __func__, i, residue);
900 rc = cyttsp5_write_config_row_(dev, ebid, i, residue,
901 row_buf);
902 row_count++;
903 if (rc)
904 dev_err(dev, "%s: Fail put row=%d r=%d\n",
905 __func__, i, rc);
906 }
907
908 if (!rc)
909 parade_debug(dev, DEBUG_LEVEL_1,
910 "%s: TT_CFG updated: rows:%d bytes:%d\n",
911 __func__, row_count, table_size);
912
913 rc = cmd->nonhid_cmd->verify_config_block_crc(dev, 0, ebid,
914 &verify_crc_status, &calculated_crc, &stored_crc);
915 if (rc || verify_crc_status)
916 dev_err(dev, "%s: CRC Failed, ebid=%d, status=%d, scrc=%X ccrc=%X\n",
917 __func__, ebid, verify_crc_status,
918 calculated_crc, stored_crc);
919 else
920 parade_debug(dev, DEBUG_LEVEL_1,
921 "%s: CRC PASS, ebid=%d, status=%d, scrc=%X ccrc=%X\n",
922 __func__, ebid, verify_crc_status,
923 calculated_crc, stored_crc);
924
925 rc = cmd->nonhid_cmd->resume_scanning(dev, 0);
926 if (rc < 0)
927 goto release;
928
929 if (ld->loader_pdata &&
930 (ld->loader_pdata->flags
931 & CY_LOADER_FLAG_CALIBRATE_AFTER_TTCONFIG_UPGRADE)) {
932 #if (KERNEL_VERSION(3, 13, 0) <= LINUX_VERSION_CODE)
933 reinit_completion(&ld->calibration_complete);
934 #else
935 INIT_COMPLETION(ld->calibration_complete);
936 #endif
937 /* set up call back for startup */
938 parade_debug(dev, DEBUG_LEVEL_2, "%s: Adding callback for calibration\n",
939 __func__);
940 rc = cmd->subscribe_attention(dev, CY_ATTEN_STARTUP,
941 CYTTSP5_LOADER_NAME, cyttsp5_calibration_attention, 0);
942 if (rc) {
943 dev_err(dev, "%s: Failed adding callback for calibration\n",
944 __func__);
945 dev_err(dev, "%s: No calibration will be performed\n",
946 __func__);
947 rc = 0;
948 } else
949 wait_for_calibration_complete = true;
950 }
951
952 release:
953 cmd->release_exclusive(dev);
954
955 exit:
956 if (!rc)
957 cmd->request_restart(dev, true);
958
959 pm_runtime_put_sync(dev);
960
961 if (wait_for_calibration_complete)
962 wait_for_completion(&ld->calibration_complete);
963
964 return rc;
965 }
966 #endif /* CYTTSP5_TTCONFIG_UPGRADE */
967
968 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
cyttsp5_get_ttconfig_crc(struct device * dev,const u8 * ttconfig_data,int ttconfig_size,u16 * crc)969 static int cyttsp5_get_ttconfig_crc(struct device *dev,
970 const u8 *ttconfig_data, int ttconfig_size, u16 *crc)
971 {
972 u16 crc_loc;
973
974 crc_loc = get_unaligned_le16(&ttconfig_data[2]);
975 if (ttconfig_size < crc_loc + 2)
976 return -EINVAL;
977
978 *crc = get_unaligned_le16(&ttconfig_data[crc_loc]);
979
980 return 0;
981 }
982
cyttsp5_get_ttconfig_version(struct device * dev,const u8 * ttconfig_data,int ttconfig_size,u16 * version)983 static int cyttsp5_get_ttconfig_version(struct device *dev,
984 const u8 *ttconfig_data, int ttconfig_size, u16 *version)
985 {
986 if (ttconfig_size < CY_TTCONFIG_VERSION_OFFSET
987 + CY_TTCONFIG_VERSION_SIZE)
988 return -EINVAL;
989
990 *version = get_unaligned_le16(
991 &ttconfig_data[CY_TTCONFIG_VERSION_OFFSET]);
992
993 return 0;
994 }
995
cyttsp5_check_ttconfig_version(struct device * dev,const u8 * ttconfig_data,int ttconfig_size)996 static int cyttsp5_check_ttconfig_version(struct device *dev,
997 const u8 *ttconfig_data, int ttconfig_size)
998 {
999 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1000 u16 cfg_crc_new;
1001 int rc;
1002
1003 if (!ld->si)
1004 return 0;
1005
1006 /* Check for config version */
1007 if (ld->loader_pdata->flags &
1008 CY_LOADER_FLAG_CHECK_TTCONFIG_VERSION) {
1009 u16 cfg_ver_new;
1010
1011 rc = cyttsp5_get_ttconfig_version(dev, ttconfig_data,
1012 ttconfig_size, &cfg_ver_new);
1013 if (rc)
1014 return 0;
1015
1016 parade_debug(dev, DEBUG_LEVEL_1, "%s: img_ver:0x%04X new_ver:0x%04X\n",
1017 __func__, ld->si->cydata.fw_ver_conf, cfg_ver_new);
1018
1019 /* Check if config version is newer */
1020 if (cfg_ver_new > ld->si->cydata.fw_ver_conf) {
1021 parade_debug(dev, DEBUG_LEVEL_1, "%s: Config version newer, will upgrade\n",
1022 __func__);
1023 return 1;
1024 }
1025
1026 parade_debug(dev, DEBUG_LEVEL_1, "%s: Config version is identical or older, will NOT upgrade\n",
1027 __func__);
1028 /* Check for config CRC */
1029 } else {
1030 rc = cyttsp5_get_ttconfig_crc(dev, ttconfig_data,
1031 ttconfig_size, &cfg_crc_new);
1032 if (rc)
1033 return 0;
1034
1035 parade_debug(dev, DEBUG_LEVEL_1, "%s: img_crc:0x%04X new_crc:0x%04X\n",
1036 __func__, ld->si->ttconfig.crc, cfg_crc_new);
1037
1038 if (cfg_crc_new != ld->si->ttconfig.crc) {
1039 parade_debug(dev, DEBUG_LEVEL_1, "%s: Config CRC different, will upgrade\n",
1040 __func__);
1041 return 1;
1042 }
1043
1044 parade_debug(dev, DEBUG_LEVEL_1, "%s: Config CRC equal, will NOT upgrade\n",
1045 __func__);
1046 }
1047
1048 return 0;
1049 }
1050
cyttsp5_check_ttconfig_version_platform(struct device * dev,struct cyttsp5_touch_config * ttconfig)1051 static int cyttsp5_check_ttconfig_version_platform(struct device *dev,
1052 struct cyttsp5_touch_config *ttconfig)
1053 {
1054 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1055 u32 fw_ver_config;
1056 u32 fw_revctrl_config;
1057
1058 if (!ld->si) {
1059 dev_info(dev, "%s: No firmware infomation found, device FW may be corrupted\n",
1060 __func__);
1061 return 0;
1062 }
1063
1064 fw_ver_config = get_unaligned_be16(ttconfig->fw_ver + 2);
1065 /* 4 middle bytes are not used */
1066 fw_revctrl_config = get_unaligned_be32(ttconfig->fw_ver + 8);
1067
1068 /* FW versions should match */
1069 if (cyttsp5_check_firmware_version(dev, fw_ver_config,
1070 fw_revctrl_config)) {
1071 dev_err(dev, "%s: FW versions mismatch\n", __func__);
1072 return 0;
1073 }
1074
1075 /* Check PowerOn Self Test, TT_CFG CRC bit */
1076 if ((ld->si->cydata.post_code & CY_POST_TT_CFG_CRC_MASK) == 0) {
1077 parade_debug(dev, DEBUG_LEVEL_1, "%s: POST, TT_CFG failed (%X), will upgrade\n",
1078 __func__, ld->si->cydata.post_code);
1079 return 1;
1080 }
1081
1082 return cyttsp5_check_ttconfig_version(dev, ttconfig->param_regs->data,
1083 ttconfig->param_regs->size);
1084 }
1085
cyttsp5_get_platform_ttconfig(struct device * dev)1086 static struct cyttsp5_touch_config *cyttsp5_get_platform_ttconfig(
1087 struct device *dev)
1088 {
1089 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1090 struct cyttsp5_touch_config **ttconfigs;
1091 struct cyttsp5_touch_config *ttconfig;
1092 u8 panel_id;
1093
1094 panel_id = cyttsp5_get_panel_id(dev);
1095 if (panel_id == PANEL_ID_NOT_ENABLED) {
1096 /* TODO: Make debug message */
1097 dev_info(dev, "%s: Panel ID not enabled, using legacy ttconfig\n",
1098 __func__);
1099 return ld->loader_pdata->ttconfig;
1100 }
1101
1102 ttconfigs = ld->loader_pdata->ttconfigs;
1103 if (!ttconfigs)
1104 return NULL;
1105
1106 /* Find TT config according to the Panel ID */
1107 while ((ttconfig = *ttconfigs++)) {
1108 if (ttconfig->panel_id == panel_id) {
1109 /* TODO: Make debug message */
1110 dev_info(dev, "%s: Found matching ttconfig:%p with Panel ID: 0x%02X\n",
1111 __func__, ttconfig, ttconfig->panel_id);
1112 return ttconfig;
1113 }
1114 parade_debug(dev, DEBUG_LEVEL_2, "%s: Found mismatching ttconfig:%p with Panel ID: 0x%02X\n",
1115 __func__, ttconfig, ttconfig->panel_id);
1116 }
1117
1118 return NULL;
1119 }
1120
upgrade_ttconfig_from_platform(struct device * dev)1121 static int upgrade_ttconfig_from_platform(struct device *dev)
1122 {
1123 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1124 struct cyttsp5_touch_config *ttconfig;
1125 struct touch_settings *param_regs;
1126 struct cyttsp5_touch_fw;
1127 int rc = -ENODEV;
1128 int upgrade;
1129
1130 if (!ld->loader_pdata) {
1131 dev_info(dev, "%s: No loader platform data\n", __func__);
1132 return rc;
1133 }
1134
1135 ttconfig = cyttsp5_get_platform_ttconfig(dev);
1136 if (!ttconfig) {
1137 dev_info(dev, "%s: No ttconfig data\n", __func__);
1138 return rc;
1139 }
1140
1141 param_regs = ttconfig->param_regs;
1142 if (!param_regs) {
1143 dev_info(dev, "%s: No touch parameters\n", __func__);
1144 return rc;
1145 }
1146
1147 if (!param_regs->data || !param_regs->size) {
1148 dev_info(dev, "%s: Invalid touch parameters\n", __func__);
1149 return rc;
1150 }
1151
1152 if (!ttconfig->fw_ver || !ttconfig->fw_vsize) {
1153 dev_info(dev, "%s: Invalid FW version for touch parameters\n",
1154 __func__);
1155 return rc;
1156 }
1157
1158 upgrade = cyttsp5_check_ttconfig_version_platform(dev, ttconfig);
1159 if (upgrade)
1160 return cyttsp5_upgrade_ttconfig(dev, param_regs->data,
1161 param_regs->size);
1162
1163 return rc;
1164 }
1165 #endif /* CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE */
1166
1167 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
cyttsp5_config_data_write(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t offset,size_t count)1168 static ssize_t cyttsp5_config_data_write(struct file *filp,
1169 struct kobject *kobj, struct bin_attribute *bin_attr,
1170 char *buf, loff_t offset, size_t count)
1171 {
1172 struct device *dev = container_of(kobj, struct device, kobj);
1173 struct cyttsp5_loader_data *data = cyttsp5_get_loader_data(dev);
1174 u8 *p;
1175
1176 parade_debug(dev, DEBUG_LEVEL_2, "%s: offset:%lld count:%zu\n",
1177 __func__, offset, count);
1178
1179 mutex_lock(&data->config_lock);
1180
1181 if (!data->config_loading) {
1182 mutex_unlock(&data->config_lock);
1183 return -ENODEV;
1184 }
1185
1186 p = krealloc(data->config_data, offset + count, GFP_KERNEL);
1187 if (!p) {
1188 kfree(data->config_data);
1189 data->config_data = NULL;
1190 mutex_unlock(&data->config_lock);
1191 return -ENOMEM;
1192 }
1193 data->config_data = p;
1194
1195 memcpy(&data->config_data[offset], buf, count);
1196 data->config_size += count;
1197
1198 mutex_unlock(&data->config_lock);
1199
1200 return count;
1201 }
1202
1203 static struct bin_attribute bin_attr_config_data = {
1204 .attr = {
1205 .name = "config_data",
1206 .mode = S_IWUSR,
1207 },
1208 .size = 0,
1209 .write = cyttsp5_config_data_write,
1210 };
1211
cyttsp5_config_loading_show(struct device * dev,struct device_attribute * attr,char * buf)1212 static ssize_t cyttsp5_config_loading_show(struct device *dev,
1213 struct device_attribute *attr, char *buf)
1214 {
1215 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1216 bool config_loading;
1217
1218 mutex_lock(&ld->config_lock);
1219 config_loading = ld->config_loading;
1220 mutex_unlock(&ld->config_lock);
1221
1222 return sprintf(buf, "%d\n", config_loading);
1223 }
1224
cyttsp5_verify_ttconfig_binary(struct device * dev,u8 * bin_config_data,int bin_config_size,u8 ** start,int * len)1225 static int cyttsp5_verify_ttconfig_binary(struct device *dev,
1226 u8 *bin_config_data, int bin_config_size, u8 **start, int *len)
1227 {
1228 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1229 int header_size;
1230 u16 config_size;
1231 u32 fw_ver_config;
1232 u32 fw_revctrl_config;
1233
1234 if (!ld->si) {
1235 dev_err(dev, "%s: No firmware infomation found, device FW may be corrupted\n",
1236 __func__);
1237 return -ENODEV;
1238 }
1239
1240 /*
1241 * We need 11 bytes for FW version control info and at
1242 * least 6 bytes in config (Length + Max Length + CRC)
1243 */
1244 header_size = bin_config_data[0] + 1;
1245 if (header_size < 11 || header_size >= bin_config_size - 6) {
1246 dev_err(dev, "%s: Invalid header size %d\n", __func__,
1247 header_size);
1248 return -EINVAL;
1249 }
1250
1251 fw_ver_config = get_unaligned_be16(&bin_config_data[1]);
1252 /* 4 middle bytes are not used */
1253 fw_revctrl_config = get_unaligned_be32(&bin_config_data[7]);
1254
1255 /* FW versions should match */
1256 if (cyttsp5_check_firmware_version(dev, fw_ver_config,
1257 fw_revctrl_config)) {
1258 dev_err(dev, "%s: FW versions mismatch\n", __func__);
1259 return -EINVAL;
1260 }
1261
1262 config_size = get_unaligned_le16(&bin_config_data[header_size]);
1263 /* Perform a simple size check (2 bytes for CRC) */
1264 if (config_size != bin_config_size - header_size - 2) {
1265 dev_err(dev, "%s: Config size invalid\n", __func__);
1266 return -EINVAL;
1267 }
1268
1269 *start = &bin_config_data[header_size];
1270 *len = bin_config_size - header_size;
1271
1272 return 0;
1273 }
1274
1275 /*
1276 * 1: Start loading TT Config
1277 * 0: End loading TT Config and perform upgrade
1278 *-1: Exit loading
1279 */
cyttsp5_config_loading_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1280 static ssize_t cyttsp5_config_loading_store(struct device *dev,
1281 struct device_attribute *attr, const char *buf, size_t size)
1282 {
1283 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1284 long value;
1285 u8 *start;
1286 int length;
1287 int rc;
1288
1289 rc = kstrtol(buf, 10, &value);
1290 if (rc < 0 || value < -1 || value > 1) {
1291 dev_err(dev, "%s: Invalid value\n", __func__);
1292 return size;
1293 }
1294
1295 mutex_lock(&ld->config_lock);
1296
1297 if (value == 1)
1298 ld->config_loading = true;
1299 else if (value == -1)
1300 ld->config_loading = false;
1301 else if (value == 0 && ld->config_loading) {
1302 ld->config_loading = false;
1303 if (ld->config_size == 0) {
1304 dev_err(dev, "%s: No config data\n", __func__);
1305 goto exit_free;
1306 }
1307
1308 rc = cyttsp5_verify_ttconfig_binary(dev,
1309 ld->config_data, ld->config_size,
1310 &start, &length);
1311 if (rc)
1312 goto exit_free;
1313
1314 rc = cyttsp5_upgrade_ttconfig(dev, start, length);
1315 }
1316
1317 exit_free:
1318 kfree(ld->config_data);
1319 ld->config_data = NULL;
1320 ld->config_size = 0;
1321
1322 mutex_unlock(&ld->config_lock);
1323
1324 if (rc)
1325 return rc;
1326
1327 return size;
1328 }
1329
1330 static DEVICE_ATTR(config_loading, S_IRUSR | S_IWUSR,
1331 cyttsp5_config_loading_show, cyttsp5_config_loading_store);
1332 #endif /* CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE */
1333
cyttsp5_fw_and_config_upgrade(struct work_struct * fw_and_config_upgrade)1334 static void cyttsp5_fw_and_config_upgrade(
1335 struct work_struct *fw_and_config_upgrade)
1336 {
1337 struct cyttsp5_loader_data *ld = container_of(fw_and_config_upgrade,
1338 struct cyttsp5_loader_data, fw_and_config_upgrade);
1339 struct device *dev = ld->dev;
1340
1341 ld->si = cmd->request_sysinfo(dev);
1342 if (!ld->si)
1343 dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
1344 __func__);
1345 #if !CYTTSP5_FW_UPGRADE
1346 dev_info(dev, "%s: No FW upgrade method selected!\n", __func__);
1347 #endif
1348
1349 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
1350 if (!upgrade_firmware_from_platform(dev, false))
1351 return;
1352 #endif
1353
1354 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1355 if (!upgrade_firmware_from_builtin(dev))
1356 return;
1357 #endif
1358
1359 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_TTCONFIG_UPGRADE
1360 if (!upgrade_ttconfig_from_platform(dev))
1361 return;
1362 #endif
1363 }
1364
1365 #if CYTTSP5_FW_UPGRADE
cyttsp5_fw_upgrade_cb(struct device * dev)1366 static int cyttsp5_fw_upgrade_cb(struct device *dev)
1367 {
1368 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
1369 if (!upgrade_firmware_from_platform(dev, false))
1370 return 1;
1371 #endif
1372
1373 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1374 if (!upgrade_firmware_from_builtin(dev))
1375 return 1;
1376 #endif
1377 return 0;
1378 }
1379 #endif
1380
1381 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
cyttsp5_forced_upgrade_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1382 static ssize_t cyttsp5_forced_upgrade_store(struct device *dev,
1383 struct device_attribute *attr, const char *buf, size_t size)
1384 {
1385 int rc = upgrade_firmware_from_platform(dev, true);
1386
1387 if (rc)
1388 return rc;
1389 return size;
1390 }
1391
1392 static DEVICE_ATTR(forced_upgrade, S_IWUSR,
1393 NULL, cyttsp5_forced_upgrade_store);
1394 #endif
1395
1396 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
cyttsp5_manual_upgrade_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1397 static ssize_t cyttsp5_manual_upgrade_store(struct device *dev,
1398 struct device_attribute *attr, const char *buf, size_t size)
1399 {
1400 struct cyttsp5_loader_data *ld = cyttsp5_get_loader_data(dev);
1401 int rc;
1402
1403 if (ld->is_manual_upgrade_enabled)
1404 return -EBUSY;
1405
1406 ld->is_manual_upgrade_enabled = 1;
1407
1408 rc = upgrade_firmware_from_class(ld->dev);
1409
1410 if (rc < 0)
1411 ld->is_manual_upgrade_enabled = 0;
1412
1413 return size;
1414 }
1415
1416 static DEVICE_ATTR(manual_upgrade, S_IWUSR,
1417 NULL, cyttsp5_manual_upgrade_store);
1418 #endif
1419
cyttsp5_loader_probe(struct device * dev,void ** data)1420 static int cyttsp5_loader_probe(struct device *dev, void **data)
1421 {
1422 struct cyttsp5_loader_data *ld;
1423 struct cyttsp5_platform_data *pdata = dev_get_platdata(dev);
1424 int rc;
1425
1426 if (!pdata || !pdata->loader_pdata) {
1427 dev_err(dev, "%s: Missing platform data\n", __func__);
1428 rc = -ENODEV;
1429 goto error_no_pdata;
1430 }
1431
1432 ld = kzalloc(sizeof(*ld), GFP_KERNEL);
1433 if (!ld) {
1434 rc = -ENOMEM;
1435 goto error_alloc_data_failed;
1436 }
1437
1438 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
1439 rc = device_create_file(dev, &dev_attr_forced_upgrade);
1440 if (rc) {
1441 dev_err(dev, "%s: Error, could not create forced_upgrade\n",
1442 __func__);
1443 goto error_create_forced_upgrade;
1444 }
1445 #endif
1446
1447 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1448 rc = device_create_file(dev, &dev_attr_manual_upgrade);
1449 if (rc) {
1450 dev_err(dev, "%s: Error, could not create manual_upgrade\n",
1451 __func__);
1452 goto error_create_manual_upgrade;
1453 }
1454 #endif
1455
1456 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
1457 rc = device_create_file(dev, &dev_attr_config_loading);
1458 if (rc) {
1459 dev_err(dev, "%s: Error, could not create config_loading\n",
1460 __func__);
1461 goto error_create_config_loading;
1462 }
1463
1464 rc = device_create_bin_file(dev, &bin_attr_config_data);
1465 if (rc) {
1466 dev_err(dev, "%s: Error, could not create config_data\n",
1467 __func__);
1468 goto error_create_config_data;
1469 }
1470 #endif
1471
1472 ld->loader_pdata = pdata->loader_pdata;
1473 ld->dev = dev;
1474 *data = ld;
1475
1476 #if CYTTSP5_FW_UPGRADE
1477 init_completion(&ld->int_running);
1478 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1479 init_completion(&ld->builtin_bin_fw_complete);
1480 #endif
1481 cmd->subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_LOADER_NAME,
1482 cyttsp5_loader_attention, CY_MODE_BOOTLOADER);
1483
1484 cmd->subscribe_attention(dev, CY_ATTEN_LOADER, CYTTSP5_LOADER_NAME,
1485 cyttsp5_fw_upgrade_cb, CY_MODE_UNKNOWN);
1486 #endif
1487 #if CYTTSP5_FW_UPGRADE || CYTTSP5_TTCONFIG_UPGRADE
1488 init_completion(&ld->calibration_complete);
1489 INIT_WORK(&ld->calibration_work, cyttsp5_calibrate_idacs);
1490 #endif
1491 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
1492 mutex_init(&ld->config_lock);
1493 #endif
1494
1495 #ifdef UPGRADE_FW_AND_CONFIG_IN_PROBE
1496 /* Call FW and config upgrade directly in probe */
1497 cyttsp5_fw_and_config_upgrade(&ld->fw_and_config_upgrade);
1498 #else
1499 INIT_WORK(&ld->fw_and_config_upgrade, cyttsp5_fw_and_config_upgrade);
1500 schedule_work(&ld->fw_and_config_upgrade);
1501 #endif
1502
1503 dev_info(dev, "%s: Successful probe %s\n", __func__, dev_name(dev));
1504 return 0;
1505
1506 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
1507 error_create_config_data:
1508 device_remove_file(dev, &dev_attr_config_loading);
1509 error_create_config_loading:
1510 #endif
1511 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1512 device_remove_file(dev, &dev_attr_manual_upgrade);
1513 error_create_manual_upgrade:
1514 #endif
1515 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
1516 device_remove_file(dev, &dev_attr_forced_upgrade);
1517 error_create_forced_upgrade:
1518 #endif
1519 kfree(ld);
1520 error_alloc_data_failed:
1521 error_no_pdata:
1522 dev_err(dev, "%s failed.\n", __func__);
1523 return rc;
1524 }
1525
cyttsp5_loader_release(struct device * dev,void * data)1526 static void cyttsp5_loader_release(struct device *dev, void *data)
1527 {
1528 struct cyttsp5_loader_data *ld = (struct cyttsp5_loader_data *)data;
1529
1530 #if CYTTSP5_FW_UPGRADE
1531 cmd->unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_LOADER_NAME,
1532 cyttsp5_loader_attention, CY_MODE_BOOTLOADER);
1533
1534 cmd->unsubscribe_attention(dev, CY_ATTEN_LOADER, CYTTSP5_LOADER_NAME,
1535 cyttsp5_fw_upgrade_cb, CY_MODE_UNKNOWN);
1536 #endif
1537 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_MANUAL_TTCONFIG_UPGRADE
1538 device_remove_bin_file(dev, &bin_attr_config_data);
1539 device_remove_file(dev, &dev_attr_config_loading);
1540 kfree(ld->config_data);
1541 #endif
1542 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_BINARY_FW_UPGRADE
1543 device_remove_file(dev, &dev_attr_manual_upgrade);
1544 #endif
1545 #ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_PLATFORM_FW_UPGRADE
1546 device_remove_file(dev, &dev_attr_forced_upgrade);
1547 #endif
1548 kfree(ld);
1549 }
1550
1551 static struct cyttsp5_module loader_module = {
1552 .name = CYTTSP5_LOADER_NAME,
1553 .probe = cyttsp5_loader_probe,
1554 .release = cyttsp5_loader_release,
1555 };
1556
cyttsp5_loader_init(void)1557 static int __init cyttsp5_loader_init(void)
1558 {
1559 int rc;
1560
1561 cmd = cyttsp5_get_commands();
1562 if (!cmd)
1563 return -EINVAL;
1564
1565 rc = cyttsp5_register_module(&loader_module);
1566 if (rc < 0) {
1567 pr_err("%s: Error, failed registering module\n",
1568 __func__);
1569 return rc;
1570 }
1571
1572 pr_info("%s: Parade TTSP FW Loader Driver (Built %s) rc=%d\n",
1573 __func__, CY_DRIVER_VERSION, rc);
1574 return 0;
1575 }
1576 module_init(cyttsp5_loader_init);
1577
cyttsp5_loader_exit(void)1578 static void __exit cyttsp5_loader_exit(void)
1579 {
1580 cyttsp5_unregister_module(&loader_module);
1581 }
1582 module_exit(cyttsp5_loader_exit);
1583
1584 MODULE_LICENSE("GPL");
1585 MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product FW Loader Driver");
1586 MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
1587