xref: /OK3568_Linux_fs/kernel/drivers/input/touchscreen/cyttsp5/cyttsp5_loader.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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