From patchwork Tue Nov 19 05:59:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Johnny.Chuang" X-Patchwork-Id: 11250887 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AB059109A for ; Tue, 19 Nov 2019 06:11:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 89CD6222A4 for ; Tue, 19 Nov 2019 06:11:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727904AbfKSGLm (ORCPT ); Tue, 19 Nov 2019 01:11:42 -0500 Received: from emcscan.emc.com.tw ([192.72.220.5]:11011 "EHLO emcscan.emc.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727324AbfKSGLl (ORCPT ); Tue, 19 Nov 2019 01:11:41 -0500 X-Greylist: delayed 695 seconds by postgrey-1.27 at vger.kernel.org; Tue, 19 Nov 2019 01:11:40 EST X-IronPort-AV: E=Sophos;i="5.56,253,1539619200"; d="scan'208";a="32944514" Received: from unknown (HELO webmail.emc.com.tw) ([192.168.10.1]) by emcscan.emc.com.tw with ESMTP; 19 Nov 2019 13:59:50 +0800 Received: from 192.168.10.23 by webmail.emc.com.tw with MailAudit ESMTP Server V5.0(71493:0:AUTH_RELAY) (envelope-from ); Tue, 19 Nov 2019 13:59:48 +0800 (CST) Received: from 192.168.55.71 by webmail.emc.com.tw with Mail2000 ESMTPA Server V7.00(101170:0:AUTH_LOGIN) (envelope-from ); Tue, 19 Nov 2019 13:59:45 +0800 (CST) From: "Johnny.Chuang" To: "'Dmitry Torokhov'" , , Cc: =?big5_tw?b?U1RSRDItsviozsBN?= , =?big5_tw?b?U1RS?= =?big5_tw?b?RDItvbK0Zrxg?= , , =?big5_tw?b?J7Hns9W1vic=?= , "'jeff'" References: <1574142739-24556-1-git-send-email-johnny.chuang@emc.com.tw> In-Reply-To: <1574142739-24556-1-git-send-email-johnny.chuang@emc.com.tw> Subject: [PATCH] Input: elants_i2c - Add Remark ID check flow in firmware update function Date: Tue, 19 Nov 2019 13:59:45 +0800 Message-ID: <003d01d59e9e$8b0a3120$a11e9360$@emc.com.tw> MIME-Version: 1.0 X-Mailer: Microsoft Outlook 14.0 thread-index: AQJWcJ1GfW6vkoLmumyMvYKuQq0ScKaQWfTg Content-Language: zh-tw x-dg-ref: PG1ldGE+PGF0IG5tPSJib2R5LnR4dCIgcD0iYzpcdXNlcnNcMDUwMTBcYXBwZGF0YVxyb2FtaW5nXDA5ZDg0OWI2LTMyZDMtNGE0MC04NWVlLTZiODRiYTI5ZTM1Ylxtc2dzXG1zZy1jODZhZjRiMy0wYTkxLTExZWEtYmNjMC03YzVjZjg3NDk0NzhcYW1lLXRlc3RcYzg2YWY0YjUtMGE5MS0xMWVhLWJjYzAtN2M1Y2Y4NzQ5NDc4Ym9keS50eHQiIHN6PSI2MDg0IiB0PSIxMzIxODYxNjc4NDkxNzk3NzkiIGg9IkE5cEYzOGY0K0MwQk1FaENIdmZlcFcxWVhBQT0iIGlkPSIiIGJsPSIwIiBibz0iMSIvPjwvbWV0YT4= x-dg-rorf: true Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org This patch add Remark ID check flow to firmware update function of elan touchscreen driver. It avoids firmware update with mismatched Remark ID. This function is supported by our latest version of boot code, but it cooperates well with earlier versions. Our driver will decide if enable Remark ID check with boot code version. Signed-off-by: Johnny Chuang --- drivers/input/touchscreen/elants_i2c.c | 108 ++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 8 deletions(-) __func__, (int)cmd_size, cmd); @@ -556,6 +563,8 @@ static int elants_i2c_initialize(struct elants_data *ts) /* hw version is available even if device in recovery state */ error2 = elants_i2c_query_hw_version(ts); + if (!error2) + error2 = elants_i2c_query_bc_version(ts); if (!error) error = error2; @@ -564,8 +573,6 @@ static int elants_i2c_initialize(struct elants_data *ts) if (!error) error = elants_i2c_query_test_version(ts); if (!error) - error = elants_i2c_query_bc_version(ts); - if (!error) error = elants_i2c_query_ts_info(ts); if (error) @@ -613,39 +620,124 @@ static int elants_i2c_fw_write_page(struct i2c_client *client, return error; } +static int elants_i2c_query_remark_id(struct elants_data *ts) { + struct i2c_client *client = ts->client; + int error; + const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 }; + u8 resp[6] = { 0 }; + + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get Remark ID failed: %d.\n", error); + return error; + } + + ts->remark_id = get_unaligned_be16(&resp[3]); + dev_info(&client->dev, "remark_id=0x%04x.\n", ts->remark_id); + + return 0; +} + +static int elants_i2c_validate_remark_id(struct elants_data *ts, + const struct firmware *fw) +{ + struct i2c_client *client = ts->client; + int error; + u16 fw_remark_id = 0; + + /* Compare TS Remark ID and FW Remark ID */ + error = elants_i2c_query_remark_id(ts); + if (error) { + dev_err(&client->dev, "failed to query Remark ID: %d\n", error); + return error; + } + + fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]); + dev_info(&client->dev, "fw_remark_id=0x%04x.\n", fw_remark_id); + if (fw_remark_id != ts->remark_id) { + dev_err(&client->dev, + "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%x.\n", + ts->remark_id, fw_remark_id); + return -ENODATA; + } + + return 0; +} + static int elants_i2c_do_update_firmware(struct i2c_client *client, const struct firmware *fw, bool force) { + struct elants_data *ts = i2c_get_clientdata(client); + static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; - const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; + const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 }; u8 buf[HEADER_SIZE]; u16 send_id; int page, n_fw_pages; int error; + bool check_remark_id = ts->iap_version >= 0x60; /* Recovery mode detection! */ if (force) { dev_dbg(&client->dev, "Recovery mode procedure\n"); + + if (check_remark_id == true) { + /* Validate Remark ID */ + error = elants_i2c_validate_remark_id(ts, fw); + if (error) { + dev_err(&client->dev, + "failed to validate Remark ID: %d\n", + error); + return error; + } + } + + error = elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); + if (error) + dev_err(&client->dev, "failed to write flash key: %d\n", + error); + error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", + error); + return error; + } + msleep(20); } else { /* Start IAP Procedure */ dev_dbg(&client->dev, "Normal IAP procedure\n"); + /* Close idle mode */ error = elants_i2c_send(client, close_idle, sizeof(close_idle)); if (error) dev_err(&client->dev, "Failed close idle: %d\n", error); msleep(60); + elants_i2c_sw_reset(client); msleep(20); - error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); - } - if (error) { - dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); - return error; + if (check_remark_id == true) { + /* Validate Remark ID */ + error = elants_i2c_validate_remark_id(ts, fw); + if (error) { + dev_err(&client->dev, "failed to validate Remark ID: %d\n", + error); + return error; + } + } + + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", + error); + return error; + } } msleep(20); -- 2.7.4 diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index d4ad24e..9a17af6 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -59,8 +59,10 @@ #define CMD_HEADER_WRITE 0x54 #define CMD_HEADER_READ 0x53 #define CMD_HEADER_6B_READ 0x5B +#define CMD_HEADER_ROM_READ 0x96 #define CMD_HEADER_RESP 0x52 #define CMD_HEADER_6B_RESP 0x9B +#define CMD_HEADER_ROM_RESP 0x95 #define CMD_HEADER_HELLO 0x55 #define CMD_HEADER_REK 0x66 @@ -128,6 +130,7 @@ struct elants_data { u8 bc_version; u8 iap_version; u16 hw_version; + u16 remark_id; unsigned int x_res; /* resolution in units/mm */ unsigned int y_res; unsigned int x_max; @@ -200,6 +203,10 @@ static int elants_i2c_execute_command(struct i2c_client *client, expected_response = CMD_HEADER_6B_RESP; break; + case CMD_HEADER_ROM_READ: + expected_response = CMD_HEADER_ROM_RESP; + break; + default: dev_err(&client->dev, "%s: invalid command %*ph\n",