From patchwork Fri Jan 18 01:09:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769259 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1220B6C2 for ; Fri, 18 Jan 2019 01:09:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F2B302EBB0 for ; Fri, 18 Jan 2019 01:09:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E3E232EBA9; Fri, 18 Jan 2019 01:09:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 788482EBA9 for ; Fri, 18 Jan 2019 01:09:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726902AbfARBJ5 (ORCPT ); Thu, 17 Jan 2019 20:09:57 -0500 Received: from hqemgate16.nvidia.com ([216.228.121.65]:14830 "EHLO hqemgate16.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726351AbfARBJ4 (ORCPT ); Thu, 17 Jan 2019 20:09:56 -0500 Received: from hqpgpgate102.nvidia.com (Not Verified[216.228.121.13]) by hqemgate16.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:09:25 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate102.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:09:55 -0800 X-PGP-Universal: processed; by hqpgpgate102.nvidia.com on Thu, 17 Jan 2019 17:09:55 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:09:53 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 1/7] usb: typec: ucsi: add get_fw_info function Date: Thu, 17 Jan 2019 17:09:03 -0800 Message-ID: <20190118010909.16161-2-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190118010909.16161-1-ajayg@nvidia.com> References: <20190118010909.16161-1-ajayg@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: BGMAIL104.nvidia.com (10.25.59.13) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773765; bh=aH8vWGbgidtoqhH1fDGjsiTjqu+LeNxww61Vk58GhCo=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: X-Originating-IP:X-ClientProxiedBy:Content-Type; b=YtUR3fUuR5wP8utGHLthWeKYETrmRDnxVm1HpJOEYRsR+U4NtVsKQ32n+4bxA2dGb KTCdesqQ50S6lMbcJm8MVsTBrNl0pjPvJ0sR2Uza+ZCY5XdgofdLvetduyYn/IGCi8 2zIP3alvUsqnOLbBHTBH6p5uM13l5oVfOuuuaXHRyiUHGZxLIb8rmjrT6Neo5hr4U4 CmQ8OJfEbKU8KXHM/SdgW95g7hiMBDwsiCQDq9njh4JxytgfMFNp8JQWzCxtkKgtMo +Irp10hgYqYD0SEjd4rINrazE6O5XUxzLf9H48xVJ9w7AxHigV0ev5HSrEtslrX3xc KlIjx3RZxeV2g== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Function is to get the details of ccg firmware and device version. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 76 ++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index de8a43bdff68..4d35279ab853 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -17,15 +17,46 @@ #include #include "ucsi.h" +struct ccg_dev_info { + u8 fw_mode:2; + u8 two_pd_ports:2; + u8 row_size_256:2; + u8:1; /* reserved */ + u8 hpi_v2_mode:1; + u8 bl_mode:1; + u8 cfgtbl_invalid:1; + u8 fw1_invalid:1; + u8 fw2_invalid:1; + u8:4; /* reserved */ + u16 silicon_id; + u16 bl_last_row; +} __packed; + +struct version_format { + u16 build; + u8 patch; + u8 min:4; + u8 maj:4; +}; + +struct version_info { + struct version_format base; + struct version_format app; +}; + struct ucsi_ccg { struct device *dev; struct ucsi *ucsi; struct ucsi_ppm ppm; struct i2c_client *client; + struct ccg_dev_info info; }; -#define CCGX_RAB_INTR_REG 0x06 -#define CCGX_RAB_UCSI_CONTROL 0x39 +#define CCGX_RAB_DEVICE_MODE 0x0000 +#define CCGX_RAB_INTR_REG 0x0006 +#define CCGX_RAB_READ_ALL_VER 0x0010 +#define CCGX_RAB_READ_FW2_VER 0x0020 +#define CCGX_RAB_UCSI_CONTROL 0x0039 #define CCGX_RAB_UCSI_CONTROL_START BIT(0) #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) @@ -220,6 +251,41 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int get_fw_info(struct ucsi_ccg *uc) +{ + struct device *dev = uc->dev; + struct version_info version[3]; + struct version_info *v; + int err, i; + + err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&version), + sizeof(version)); + if (err < 0) + return err; + + for (i = 1; i < ARRAY_SIZE(version); i++) { + v = &version[i]; + dev_dbg(dev, + "FW%d Version: %c%c v%x.%x%x, [Base %d.%d.%d.%d]\n", + i, (v->app.build >> 8), (v->app.build & 0xFF), + v->app.patch, v->app.maj, v->app.min, + v->base.maj, v->base.min, v->base.patch, + v->base.build); + } + + err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), + sizeof(uc->info)); + if (err < 0) + return err; + + dev_dbg(dev, "fw_mode: %d\n", uc->info.fw_mode); + dev_dbg(dev, "fw1_invalid: %d\n", uc->info.fw1_invalid); + dev_dbg(dev, "fw2_invalid: %d\n", uc->info.fw2_invalid); + dev_dbg(dev, "silicon_id: 0x%04x\n", uc->info.silicon_id); + + return 0; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -248,6 +314,12 @@ static int ucsi_ccg_probe(struct i2c_client *client, return status; } + status = get_fw_info(uc); + if (status < 0) { + dev_err(uc->dev, "get_fw_info failed - %d\n", status); + return status; + } + status = devm_request_threaded_irq(dev, client->irq, NULL, ccg_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, From patchwork Fri Jan 18 01:09:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769261 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 075F4139A for ; Fri, 18 Jan 2019 01:10:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E58832EBA9 for ; Fri, 18 Jan 2019 01:10:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D98A82EBC5; Fri, 18 Jan 2019 01:10:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1A72C2EBB0 for ; Fri, 18 Jan 2019 01:10:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726351AbfARBKE (ORCPT ); Thu, 17 Jan 2019 20:10:04 -0500 Received: from hqemgate14.nvidia.com ([216.228.121.143]:4135 "EHLO hqemgate14.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725981AbfARBKE (ORCPT ); Thu, 17 Jan 2019 20:10:04 -0500 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate14.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:09:46 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:10:01 -0800 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Thu, 17 Jan 2019 17:10:01 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:09:58 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 2/7] usb: typec: ucsi: add ccg command framework Date: Thu, 17 Jan 2019 17:09:04 -0800 Message-ID: <20190118010909.16161-3-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190118010909.16161-1-ajayg@nvidia.com> References: <20190118010909.16161-1-ajayg@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: BGMAIL104.nvidia.com (10.25.59.13) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773786; bh=JlHVU+abNddxGe0i+W/xgC8UjfWv0X1+LddrzCphZoM=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: X-Originating-IP:X-ClientProxiedBy:Content-Type; b=R5UHTEjcvRJmc0ZDEKQxS8kQ+Fm/uLkDwTtmH2rEIXS1UMN0muZl3FY1Z/3R2mKA6 /qU7UX9wkGAc6q9aMYVv/mdIU+80qkM/Jl2pHvduQCLTwYXeFXokfCpn/H4hLlUQMU 5fTgyQNkX/pBOYo0HOBR+PADoyUkbt/vmdwWDtkW+2ElH4hOWqv+4uzhuN61lkpjra 9avPcst6YGQ74GalsTxOZ7+Q6t4IexgsPYSqKVW2x2tELwEiHdG3Q3bXlKera4CRTn 1EChACEA/lEB1hZjzmu5DSpS5scCljisw3ZUtFhct/ycutsl8LovbmAlzuwE0pTQ6h Sd/+rmABHnuMg== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Used to send command to ccg controller Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 252 ++++++++++++++++++++++++++++-- 1 file changed, 243 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 4d35279ab853..dce9126b6a37 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -17,6 +17,29 @@ #include #include "ucsi.h" +#define CCGX_RAB_DEVICE_MODE 0x0000 +#define CCGX_RAB_INTR_REG 0x0006 +#define DEV_INT BIT(0) +#define PORT0_INT BIT(1) +#define PORT1_INT BIT(2) +#define UCSI_READ_INT BIT(7) +#define CCGX_RAB_READ_ALL_VER 0x0010 +#define CCGX_RAB_READ_FW2_VER 0x0020 +#define CCGX_RAB_UCSI_CONTROL 0x0039 +#define CCGX_RAB_UCSI_CONTROL_START BIT(0) +#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) +#define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) +#define DEV_REG_IDX CCGX_RAB_DEVICE_MODE +#define CCGX_RAB_RESPONSE 0x007E +#define ASYNC_EVENT BIT(7) + +/* CCGx events & async msg codes */ +#define RESET_COMPLETE 0x80 +#define EVENT_INDEX RESET_COMPLETE +#define PORT_CONNECT_DET 0x84 +#define PORT_DISCONNECT_DET 0x85 +#define ROLE_SWAP_COMPELETE 0x87 + struct ccg_dev_info { u8 fw_mode:2; u8 two_pd_ports:2; @@ -44,23 +67,113 @@ struct version_info { struct version_format app; }; +/* CCGx response codes */ +enum ccg_resp_code { + CMD_NO_RESP = 0x00, + CMD_SUCCESS = 0x02, + FLASH_DATA_AVAILABLE = 0x03, + CMD_INVALID = 0x05, + FLASH_UPDATE_FAIL = 0x07, + INVALID_FW = 0x08, + INVALID_ARG = 0x09, + CMD_NOT_SUPPORT = 0x0A, + TRANSACTION_FAIL = 0x0C, + PD_CMD_FAIL = 0x0D, + UNDEF_ERROR = 0x0F, + INVALID_RESP = 0x10, +}; + +static const char * const ccg_resp_strs[] = { + /* 0x00 */ "No Response.", + /* 0x01 */ "0x01", + /* 0x02 */ "HPI Command Success.", + /* 0x03 */ "Flash Data Available in data memory.", + /* 0x04 */ "0x04", + /* 0x05 */ "Invalid Command.", + /* 0x06 */ "0x06", + /* 0x07 */ "Flash write operation failed.", + /* 0x08 */ "Firmware validity check failed.", + /* 0x09 */ "Command failed due to invalid arguments.", + /* 0x0A */ "Command not supported in the current mode.", + /* 0x0B */ "0x0B", + /* 0x0C */ "Transaction Failed. GOOD_CRC was not received.", + /* 0x0D */ "PD Command Failed.", + /* 0x0E */ "0x0E", + /* 0x0F */ "Undefined Error", +}; + +static const char * const ccg_evt_strs[] = { + /* 0x80 */ "Reset Complete.", + /* 0x81 */ "Message queue overflow detected.", + /* 0x82 */ "Overcurrent Detected", + /* 0x83 */ "Overvoltage Detected", + /* 0x84 */ "Type-C Port Connect Detected", + /* 0x85 */ "Type-C Port Disconnect Detected", + /* 0x86 */ "PD Contract Negotiation Complete", + /* 0x87 */ "SWAP Complete", + /* 0x88 */ "0x88", + /* 0x89 */ "0x89", + /* 0x8A */ "PS_RDY Message Received", + /* 0x8B */ "GotoMin Message Received.", + /* 0x8C */ "Accept Message Received", + /* 0x8D */ "Reject Message Received", + /* 0x8E */ "Wait Message Received", + /* 0x8F */ "Hard Reset Received", + /* 0x90 */ "VDM Received", + /* 0x91 */ "Source Capabilities Message Received", + /* 0x92 */ "Sink Capabilities Message Received", + /* 0x93 */ "Display Port Alternate Mode entered", + /* 0x94 */ "Display Port device connected at UFP_U", + /* 0x95 */ "Display port device not connected at UFP_U", + /* 0x96 */ "Display port SID not found in Discover SID process", + /* 0x97 */ "Multiple SVIDs discovered along with DisplayPort SID", + /* 0x98 */ "DP Functionality not supported by Cable", + /* 0x99 */ "Display Port Configuration not supported by UFP", + /* 0x9A */ "Hard Reset Sent to Port Partner", + /* 0x9B */ "Soft Reset Sent to Port Partner", + /* 0x9C */ "Cable Reset Sent to EMCA", + /* 0x9D */ "Source Disabled State Entered", + /* 0x9E */ "Sender Response Timer Timeout", + /* 0x9F */ "No VDM Response Received", + /* 0xA0 */ "Unexpected Voltage on Vbus", + /* 0xA1 */ "Type-C Error Recovery", + /* 0xA2 */ "0xA2", + /* 0xA3 */ "0xA3", + /* 0xA4 */ "0xA4", + /* 0xA5 */ "0xA5", + /* 0xA6 */ "EMCA Detected", + /* 0xA7 */ "0xA7", + /* 0xA8 */ "0xA8", + /* 0xA9 */ "0xA9", + /* 0xAA */ "Rp Change Detected", +}; + +struct ccg_cmd { + u16 reg; + u32 data; + int len; + int delay; /* ms delay for cmd timeout */ +}; + +struct ccg_resp { + u8 code; + u8 length; +}; + struct ucsi_ccg { struct device *dev; struct ucsi *ucsi; struct ucsi_ppm ppm; struct i2c_client *client; struct ccg_dev_info info; + /* CCG HPI communication flags */ + unsigned long flags; +#define RESET_PENDING 0 +#define DEV_CMD_PENDING 1 + struct ccg_resp dev_resp; + u8 cmd_resp; }; -#define CCGX_RAB_DEVICE_MODE 0x0000 -#define CCGX_RAB_INTR_REG 0x0006 -#define CCGX_RAB_READ_ALL_VER 0x0010 -#define CCGX_RAB_READ_FW2_VER 0x0020 -#define CCGX_RAB_UCSI_CONTROL 0x0039 -#define CCGX_RAB_UCSI_CONTROL_START BIT(0) -#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) -#define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) - static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) { struct i2c_client *client = uc->client; @@ -286,6 +399,127 @@ static int get_fw_info(struct ucsi_ccg *uc) return 0; } +static inline bool invalid_resp(int code) +{ + return (code >= INVALID_RESP); +} + +static inline bool invalid_evt(int code) +{ + unsigned long num_of_events = ARRAY_SIZE(ccg_evt_strs); + + return (code >= (EVENT_INDEX + num_of_events)) || (code < EVENT_INDEX); +} + +static void ccg_process_response(struct ucsi_ccg *uc) +{ + struct device *dev = uc->dev; + + if (uc->dev_resp.code & ASYNC_EVENT) { + if (uc->dev_resp.code == RESET_COMPLETE) { + if (test_bit(RESET_PENDING, &uc->flags)) + uc->cmd_resp = uc->dev_resp.code; + dev_info(dev, "CCG reset complete\n"); + get_fw_info(uc); + } + + if (!invalid_evt(uc->dev_resp.code)) + dev_dbg(dev, "%s\n", + ccg_evt_strs[uc->dev_resp.code - EVENT_INDEX]); + else + dev_err(dev, "invalid evt %d\n", uc->dev_resp.code); + } else { + if (test_bit(DEV_CMD_PENDING, &uc->flags)) { + uc->cmd_resp = uc->dev_resp.code; + clear_bit(DEV_CMD_PENDING, &uc->flags); + } else { + dev_err(dev, "dev resp 0x%04x but no cmd pending\n", + uc->dev_resp.code); + } + } +} + +static int ccg_read_response(struct ucsi_ccg *uc) +{ + unsigned long target = jiffies + msecs_to_jiffies(1000); + struct device *dev = uc->dev; + u8 intval; + int status; + + /* wait for interrupt status to get updated */ + do { + status = ccg_read(uc, CCGX_RAB_INTR_REG, &intval, + sizeof(intval)); + if (status < 0) + return status; + + if (intval & DEV_INT) + break; + usleep_range(500, 600); + } while (time_is_after_jiffies(target)); + + if (time_is_before_jiffies(target)) { + dev_err(dev, "response timeout error\n"); + return -ETIME; + } + + status = ccg_read(uc, CCGX_RAB_RESPONSE, (u8 *)&uc->dev_resp, + sizeof(uc->dev_resp)); + if (status < 0) + return status; + + dev_dbg(dev, "dev event code: 0x%02x, data len: %d\n", + uc->dev_resp.code, uc->dev_resp.length); + + status = ccg_write(uc, CCGX_RAB_INTR_REG, &intval, sizeof(intval)); + if (status < 0) + return status; + + return 0; +} + +/* Caller must hold uc->lock */ +static int ccg_send_command(struct ucsi_ccg *uc, struct ccg_cmd *cmd) +{ + struct device *dev = uc->dev; + int ret; + + switch (cmd->reg & 0xF000) { + case DEV_REG_IDX: + set_bit(DEV_CMD_PENDING, &uc->flags); + break; + default: + dev_err(dev, "invalid cmd register\n"); + break; + } + + ret = ccg_write(uc, cmd->reg, (u8 *)&cmd->data, cmd->len); + if (ret < 0) + return ret; + + dev_dbg(dev, "reg=0x%04x data=0x%08x delay=%d\n", + cmd->reg, cmd->data, cmd->delay); + + msleep(cmd->delay); + + ret = ccg_read_response(uc); + if (ret < 0) { + dev_err(dev, "response read error\n"); + switch (cmd->reg & 0xF000) { + case DEV_REG_IDX: + clear_bit(DEV_CMD_PENDING, &uc->flags); + break; + default: + dev_err(dev, "invalid cmd register\n"); + break; + } + return -EIO; + } + ccg_process_response(uc); + + return uc->cmd_resp; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { From patchwork Fri Jan 18 01:09:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769263 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7A5CA139A for ; Fri, 18 Jan 2019 01:10:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 675682EBA9 for ; Fri, 18 Jan 2019 01:10:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5B58A2EBBB; Fri, 18 Jan 2019 01:10:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 11F2D2EBA9 for ; Fri, 18 Jan 2019 01:10:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726411AbfARBKH (ORCPT ); Thu, 17 Jan 2019 20:10:07 -0500 Received: from hqemgate16.nvidia.com ([216.228.121.65]:14843 "EHLO hqemgate16.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725981AbfARBKH (ORCPT ); Thu, 17 Jan 2019 20:10:07 -0500 Received: from hqpgpgate102.nvidia.com (Not Verified[216.228.121.13]) by hqemgate16.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:09:35 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate102.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:10:06 -0800 X-PGP-Universal: processed; by hqpgpgate102.nvidia.com on Thu, 17 Jan 2019 17:10:06 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:10:03 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 3/7] usb: typec: ucsi: add port num info Date: Thu, 17 Jan 2019 17:09:05 -0800 Message-ID: <20190118010909.16161-4-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190118010909.16161-1-ajayg@nvidia.com> References: <20190118010909.16161-1-ajayg@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: BGMAIL104.nvidia.com (10.25.59.13) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773775; bh=pYQzRDbsaJsIAfOsogYmxGT+pyJ9bNpwXo0AfBC9/RQ=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: X-Originating-IP:X-ClientProxiedBy:Content-Type; b=TbXajW4FtXwLTSI0ChAUl7wWTPSIFMusx64ln695MVdQKAROeI4K3DJBXNI6X4/15 AhlrGM6XBH+y6B6KBMIsexnkN0ms1m9azc2WECk+lHt/8uy8Ms9Y56qGkATfPdL6EE fk4Bq5B0Eh2GXedQvwcStt8yTk90hJTqC1RTmdSLvz0bqmGTnObv6lIq2Kq/PjK7O/ Q5jOju+FJFDvJX32/iKKsSai9t1aWwmHTsiUq9Hkhmne6CGd8X60/NzBcwa3mj0K6D sQeht+9VtXkgTHXlLZbVMb5rBc9N1QTDLOge3A7ylnh5WHVWK3ms4awfq6XZ6f9JPz 2c74LSIgJvbMg== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Read PD port number information and save. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index dce9126b6a37..b30ca51120a3 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -172,6 +172,7 @@ struct ucsi_ccg { #define DEV_CMD_PENDING 1 struct ccg_resp dev_resp; u8 cmd_resp; + int port_num; }; static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -554,6 +555,11 @@ static int ucsi_ccg_probe(struct i2c_client *client, return status; } + if (uc->info.two_pd_ports) + uc->port_num = 2; + else + uc->port_num = 1; + status = devm_request_threaded_irq(dev, client->irq, NULL, ccg_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, From patchwork Fri Jan 18 01:09:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769265 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8862F6C2 for ; Fri, 18 Jan 2019 01:10:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 737162EBA9 for ; Fri, 18 Jan 2019 01:10:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 673B12EBBB; Fri, 18 Jan 2019 01:10:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D45252EBA9 for ; Fri, 18 Jan 2019 01:10:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726834AbfARBKM (ORCPT ); Thu, 17 Jan 2019 20:10:12 -0500 Received: from hqemgate16.nvidia.com ([216.228.121.65]:14848 "EHLO hqemgate16.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725981AbfARBKM (ORCPT ); Thu, 17 Jan 2019 20:10:12 -0500 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate16.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:09:39 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:10:09 -0800 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Thu, 17 Jan 2019 17:10:09 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:10:06 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 4/7] usb: typec: ucsi: add cmd used for fw flashing Date: Thu, 17 Jan 2019 17:09:06 -0800 Message-ID: <20190118010909.16161-5-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190118010909.16161-1-ajayg@nvidia.com> References: <20190118010909.16161-1-ajayg@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: BGMAIL104.nvidia.com (10.25.59.13) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773779; bh=GtneH8diyDESYSpmk5DRS/VizAoiZ8WX0Y1nFL28EX4=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: X-Originating-IP:X-ClientProxiedBy:Content-Type; b=A4aIJBclVmGhoXOGlbKSr0dt2sYXPvwYJiW60yuwpoUn4ZLFlAIXcbsISkDls8YGc u6RIWvohetmqU+Z48HKn8G4ZSwzKIZL50VoNoooeQNbwB9M2ouUjahnTCsugvm079x 1bKJ97vsMW6HtWBcOiIg+TLU/ivTRrel9uyaz2qrFybmorBlM/Z6arAskSnXU77wVI Qig56IbIs+WU6q3kFoHr0cLjl08V5aAXf4dXMMxGLnFqTnSfvjdIFxzPOMJK2R7Kxw ik3po1706vZFYj36sstR8p1Bd+Xm4V9qgWrgHqY/x01+5LzPmNVxsN5SB2hKMw0BsE 5gSNeE+0wtrFg== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Adding support for commands which will be used for firmware flashing. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 216 ++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index b30ca51120a3..5f341934a5af 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -23,13 +23,34 @@ #define PORT0_INT BIT(1) #define PORT1_INT BIT(2) #define UCSI_READ_INT BIT(7) +#define CCGX_RAB_JUMP_TO_BOOT 0x0007 +#define TO_BOOT 'J' +#define TO_ALT_FW 'A' +#define CCGX_RAB_RESET_REQ 0x0008 +#define RESET_SIG 'R' +#define CMD_RESET_I2C 0x0 +#define CMD_RESET_DEV 0x1 +#define CCGX_RAB_ENTER_FLASHING 0x000A +#define FLASH_ENTER_SIG 'P' +#define CCGX_RAB_VALIDATE_FW 0x000B +#define CCGX_RAB_FLASH_ROW_RW 0x000C +#define FLASH_SIG 'F' +#define FLASH_RD_CMD 0x0 +#define FLASH_WR_CMD 0x1 +#define FLASH_FWCT1_WR_CMD 0x2 +#define FLASH_FWCT2_WR_CMD 0x3 +#define FLASH_FWCT_SIG_WR_CMD 0x4 #define CCGX_RAB_READ_ALL_VER 0x0010 #define CCGX_RAB_READ_FW2_VER 0x0020 #define CCGX_RAB_UCSI_CONTROL 0x0039 #define CCGX_RAB_UCSI_CONTROL_START BIT(0) #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) +#define REG_FLASH_RW_MEM 0x0200 #define DEV_REG_IDX CCGX_RAB_DEVICE_MODE +#define CCGX_RAB_PDPORT_ENABLE 0x002C +#define PDPORT_1 BIT(0) +#define PDPORT_2 BIT(1) #define CCGX_RAB_RESPONSE 0x007E #define ASYNC_EVENT BIT(7) @@ -40,6 +61,13 @@ #define PORT_DISCONNECT_DET 0x85 #define ROLE_SWAP_COMPELETE 0x87 +/* ccg firmware */ +#define CYACD_LINE_SIZE 527 +#define CCG4_ROW_SIZE 256 +#define FW1_METADATA_ROW 0x1FF +#define FW2_METADATA_ROW 0x1FE +#define FW_CFG_TABLE_SIG_SIZE 256 + struct ccg_dev_info { u8 fw_mode:2; u8 two_pd_ports:2; @@ -173,6 +201,7 @@ struct ucsi_ccg { struct ccg_resp dev_resp; u8 cmd_resp; int port_num; + struct mutex lock; /* to sync between user and driver thread */ }; static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -521,6 +550,193 @@ static int ccg_send_command(struct ucsi_ccg *uc, struct ccg_cmd *cmd) return uc->cmd_resp; } +static int ccg_cmd_enter_flashing(struct ucsi_ccg *uc) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_ENTER_FLASHING; + cmd.data = FLASH_ENTER_SIG; + cmd.len = 1; + cmd.delay = 50; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "enter flashing failed ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ccg_cmd_reset(struct ucsi_ccg *uc, bool extra_delay) +{ + struct ccg_cmd cmd; + u8 *p; + int ret; + + p = (u8 *)&cmd.data; + cmd.reg = CCGX_RAB_RESET_REQ; + p[0] = RESET_SIG; + p[1] = CMD_RESET_DEV; + cmd.len = 2; + cmd.delay = 2000 + (extra_delay ? 3000 : 0); + + mutex_lock(&uc->lock); + + set_bit(RESET_PENDING, &uc->flags); + + ret = ccg_send_command(uc, &cmd); + if (ret != RESET_COMPLETE) + goto err_clear_flag; + + ret = 0; + +err_clear_flag: + clear_bit(RESET_PENDING, &uc->flags); + + mutex_unlock(&uc->lock); + + return ret; +} + +static int ccg_cmd_port_control(struct ucsi_ccg *uc, bool enable) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_PDPORT_ENABLE; + if (enable) + cmd.data = (uc->port_num == 1) ? + PDPORT_1 : (PDPORT_1 | PDPORT_2); + else + cmd.data = 0x0; + cmd.len = 1; + cmd.delay = 10; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "port control failed ret=%d\n", ret); + return ret; + } + return 0; +} + +static int ccg_cmd_jump_boot_mode(struct ucsi_ccg *uc, int bl_mode) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_JUMP_TO_BOOT; + + if (bl_mode) + cmd.data = TO_BOOT; + else + cmd.data = TO_ALT_FW; + + cmd.len = 1; + cmd.delay = 100; + + mutex_lock(&uc->lock); + + set_bit(RESET_PENDING, &uc->flags); + + ret = ccg_send_command(uc, &cmd); + if (ret != RESET_COMPLETE) + goto err_clear_flag; + + ret = 0; + +err_clear_flag: + clear_bit(RESET_PENDING, &uc->flags); + + mutex_unlock(&uc->lock); + + return ret; +} + +static int +ccg_cmd_write_flash_row(struct ucsi_ccg *uc, u16 row, + const void *data, u8 fcmd) +{ + struct i2c_client *client = uc->client; + struct ccg_cmd cmd; + u8 buf[CCG4_ROW_SIZE + 2]; + u8 *p; + int ret; + + /* Copy the data into the flash read/write memory. */ + buf[0] = REG_FLASH_RW_MEM & 0xFF; + buf[1] = REG_FLASH_RW_MEM >> 8; + + memcpy(buf + 2, data, CCG4_ROW_SIZE); + + mutex_lock(&uc->lock); + + ret = i2c_master_send(client, buf, CCG4_ROW_SIZE + 2); + if (ret != CCG4_ROW_SIZE + 2) { + dev_err(uc->dev, "REG_FLASH_RW_MEM write fail %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + /* Use the FLASH_ROW_READ_WRITE register to trigger */ + /* writing of data to the desired flash row */ + p = (u8 *)&cmd.data; + cmd.reg = CCGX_RAB_FLASH_ROW_RW; + p[0] = FLASH_SIG; + p[1] = fcmd; + p[2] = row & 0xFF; + p[3] = row >> 8; + cmd.len = 4; + cmd.delay = 50; + if (fcmd == FLASH_FWCT_SIG_WR_CMD) + cmd.delay += 400; + if (row == 510) + cmd.delay += 220; + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) { + dev_err(uc->dev, "write flash row failed ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) +{ + struct ccg_cmd cmd; + int ret; + + cmd.reg = CCGX_RAB_VALIDATE_FW; + cmd.data = fwid; + cmd.len = 1; + cmd.delay = 500; + + mutex_lock(&uc->lock); + + ret = ccg_send_command(uc, &cmd); + + mutex_unlock(&uc->lock); + + if (ret != CMD_SUCCESS) + return ret; + + return 0; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { From patchwork Fri Jan 18 01:12:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769267 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E5DCF6C2 for ; Fri, 18 Jan 2019 01:13:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B6E542EBB0 for ; Fri, 18 Jan 2019 01:13:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A56662EBC5; Fri, 18 Jan 2019 01:13:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BDEFF2EBB0 for ; Fri, 18 Jan 2019 01:12:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726366AbfARBM7 (ORCPT ); Thu, 17 Jan 2019 20:12:59 -0500 Received: from hqemgate15.nvidia.com ([216.228.121.64]:11349 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726182AbfARBM6 (ORCPT ); Thu, 17 Jan 2019 20:12:58 -0500 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:12:35 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:12:56 -0800 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Thu, 17 Jan 2019 17:12:56 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:12:54 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 5/7] usb: typec: ucsi: add fw update needed check Date: Thu, 17 Jan 2019 17:12:38 -0800 Message-ID: <20190118011238.16210-1-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: DRBGMAIL102.nvidia.com (10.18.16.21) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773955; bh=r94cYJfY/B9CqqgjZfPMkRVlE2oG4de8lrV6jOfBdJ4=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: X-NVConfidentiality:MIME-Version:X-Originating-IP: X-ClientProxiedBy:Content-Type; b=VMRw2f72aH/KNWWGfzJWY4bUpIdtpCSQRUS5Vcwu2PL6IeBwvVv9cb2JdU4z4d9Zs CMaqlKbGnk1iOtgc1msIy8Doeoxb/KXiEtI9uOnTjHP5y21t5QQLy3erCs/e7JqSBC P3TQn361X1BssQ3utw2cfqKLrgjlHMOM2jDRq4a4qRvkPXsZT/tPoGPIzO+wBCevEz t9NGFHTayElqMjus59Orgg5wzw3gHbJxIj2uL/kWTFLSKMvfTVoHrrkcMbE5Lu0xSk /7tZYcgkVa+qRGPekIYLg6ThOlI1DpwZpSK7FbCnSfkv+YoRA1xZbSO1YppttrsXgZ TTUcwx3EaIHhA== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This will be needed to check if latest fw is already flashed. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 139 ++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 5f341934a5af..6069a9f60d1e 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -17,6 +18,8 @@ #include #include "ucsi.h" +static int secondary_fw_min_ver = 41; +module_param(secondary_fw_min_ver, int, 0660); #define CCGX_RAB_DEVICE_MODE 0x0000 #define CCGX_RAB_INTR_REG 0x0006 #define DEV_INT BIT(0) @@ -68,6 +71,27 @@ #define FW2_METADATA_ROW 0x1FE #define FW_CFG_TABLE_SIG_SIZE 256 +enum enum_fw_mode { + BOOT, /* bootloader */ + FW1, /* FW partition-1 */ + FW2, /* FW partition-2 */ + FW_INVALID, +}; + +enum enum_flash_mode { + SECONDARY_BL, /* update secondary using bootloader */ + SECONDARY, /* update secondary using primary */ + PRIMARY, /* update primary */ + FLASH_NOT_NEEDED, /* update not required */ + FLASH_INVALID, +}; + +static const char * const ccg_fw_names[] = { + /* 0x00 */ "ccg_boot.cyacd", + /* 0x01 */ "ccg_2.cyacd", + /* 0x02 */ "ccg_1.cyacd", +}; + struct ccg_dev_info { u8 fw_mode:2; u8 two_pd_ports:2; @@ -95,6 +119,20 @@ struct version_info { struct version_format app; }; +struct fw_config_table { + u32 identity; + u16 table_size; + u8 fwct_version; + u8 is_key_change; + u8 guid[16]; + struct version_format base; + struct version_format app; + u8 primary_fw_digest[32]; + u32 key_exp_length; + u8 key_modulus[256]; + u8 key_exp[4]; +}; + /* CCGx response codes */ enum ccg_resp_code { CMD_NO_RESP = 0x00, @@ -737,6 +775,107 @@ static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) return 0; } +static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, + struct version_format *app) +{ + const struct firmware *fw = NULL; + struct device *dev = uc->dev; + struct fw_config_table fw_cfg; + u32 cur_version, new_version; + bool is_later = false; + + if (request_firmware(&fw, fw_name, dev) != 0) { + dev_err(dev, "error: Failed to open cyacd file %s\n", fw_name); + return false; + } + + /* + * check if signed fw + * last part of fw image is fw cfg table and signature + */ + if (fw->size < sizeof(fw_cfg) + FW_CFG_TABLE_SIG_SIZE) + goto not_signed_fw; + + memcpy((uint8_t *)&fw_cfg, fw->data + fw->size - + sizeof(fw_cfg) - FW_CFG_TABLE_SIG_SIZE, sizeof(fw_cfg)); + + if (fw_cfg.identity != ('F' | ('W' << 8) | ('C' << 16) | ('T' << 24))) { + dev_info(dev, "not a signed image\n"); + goto not_signed_fw; + } + + /* compare input version with FWCT version */ + cur_version = app->build | (app->patch << 16) | + ((app->min | (app->maj << 4)) << 24); + + new_version = fw_cfg.app.build | (fw_cfg.app.patch << 16) | + ((fw_cfg.app.min | (fw_cfg.app.maj << 4)) << 24); + + dev_dbg(dev, "compare current %08x and new version %08x\n", + cur_version, new_version); + + if (new_version > cur_version) { + dev_dbg(dev, "new firmware file version is later\n"); + is_later = true; + } else { + dev_dbg(dev, "new firmware file version is same or earlier\n"); + } + +not_signed_fw: + release_firmware(fw); + return is_later; +} + +static int ccg_fw_update_needed(struct ucsi_ccg *uc, + enum enum_flash_mode *mode) +{ + struct device *dev = uc->dev; + int err; + struct version_info version[3]; + + err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), + sizeof(uc->info)); + if (err) { + dev_err(dev, "read device mode failed\n"); + return err; + } + + err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)version, + sizeof(version)); + if (err) { + dev_err(dev, "read device mode failed\n"); + return err; + } + + dev_dbg(dev, "check if fw upgrade required %x %x %x %x %x %x %x %x\n", + version[FW1].base.build, version[FW1].base.patch, + version[FW1].base.min, version[FW1].base.maj, + version[FW2].app.build, version[FW2].app.patch, + version[FW2].app.min, version[FW2].app.maj); + + if (memcmp(&version[FW1], "\0\0\0\0\0\0\0\0", + sizeof(struct version_info)) == 0) { + dev_info(dev, "secondary fw is not flashed\n"); + *mode = SECONDARY_BL; + } else if (version[FW1].base.build < secondary_fw_min_ver) { + dev_info(dev, "secondary fw version is too low (< %d)\n", + secondary_fw_min_ver); + *mode = SECONDARY; + } else if (memcmp(&version[FW2], "\0\0\0\0\0\0\0\0", + sizeof(struct version_info)) == 0) { + dev_info(dev, "primary fw is not flashed\n"); + *mode = PRIMARY; + } else if (ccg_check_fw_version(uc, ccg_fw_names[PRIMARY], + &version[FW2].app)) { + dev_info(dev, "found primary fw with later version\n"); + *mode = PRIMARY; + } else { + dev_info(dev, "secondary and primary fw are the latest\n"); + *mode = FLASH_NOT_NEEDED; + } + return 0; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { From patchwork Fri Jan 18 01:13:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769269 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B7C0C139A for ; Fri, 18 Jan 2019 01:13:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A22142EBB0 for ; Fri, 18 Jan 2019 01:13:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9366C2EBC5; Fri, 18 Jan 2019 01:13:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E8352EBB0 for ; Fri, 18 Jan 2019 01:13:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726398AbfARBN2 (ORCPT ); Thu, 17 Jan 2019 20:13:28 -0500 Received: from hqemgate16.nvidia.com ([216.228.121.65]:15002 "EHLO hqemgate16.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726182AbfARBN2 (ORCPT ); Thu, 17 Jan 2019 20:13:28 -0500 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate16.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:12:56 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:13:27 -0800 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Thu, 17 Jan 2019 17:13:27 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:13:25 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 6/7] usb: typec: ucsi: add check for supported vendor Date: Thu, 17 Jan 2019 17:13:02 -0800 Message-ID: <20190118011302.16256-1-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: DRBGMAIL101.nvidia.com (10.18.16.20) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547773976; bh=7YHK99n5BUAVtCgkRbmhZXBMW1qr03ZOp07qOVlHk0M=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: X-NVConfidentiality:MIME-Version:X-Originating-IP: X-ClientProxiedBy:Content-Type; b=hPRAFZbtDeDJA6TAXDLpUnGn43PQ7BKSg/EQHsqNUzYcb9nS+GpEYp/QaVLIiq7Ax XDtt9y56k5By+qJkBa2Yq+kKb/Uz/nJz+RfvQHaQD33dVbQM+N39ZJOh4PeWThgk3H +jsehxtQlQ6DUyaI46lSdvXWbVQsaji9Dj6P3q1kJpdEvrHNHxr+FBL9j2GYAhIOoV SufZEVQwLyHyu+fTuOazoVlvTiZyQFNBfgnEy7nyH0UiIFd4jz40sNEmn8hB+gGBfb hSpxDMJ9WIKdECob4MUWwt2X4qb53URUFvNKSOBGrUhoWg4gVA7MxBBpJZWAOiPJEO QM2ow69THwxpQ== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Added check to see the currently flashed or new firmware being flashed is from a supported vendor. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 6069a9f60d1e..1aa6ede764b5 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -775,6 +775,30 @@ static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) return 0; } +static bool ccg_check_vendor_version(struct ucsi_ccg *uc, + struct version_format *app, + struct fw_config_table *fw_cfg) +{ + struct device *dev = uc->dev; + + /* Check if the fw build is for supported vendors. + * Add all supported vendors here. + */ + if (app->build != (('n' << 8) | 'v')) { + dev_info(dev, "current fw is not from supported vendor\n"); + return false; + } + + /* Check if the new fw build is for supported vendors + * Add all supported vendors here. + */ + if (fw_cfg->app.build != (('n' << 8) | 'v')) { + dev_info(dev, "new fw is not from supported vendor\n"); + return false; + } + return true; +} + static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, struct version_format *app) { @@ -814,6 +838,9 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, dev_dbg(dev, "compare current %08x and new version %08x\n", cur_version, new_version); + if (!ccg_check_vendor_version(uc, app, &fw_cfg)) + goto not_supported_version; + if (new_version > cur_version) { dev_dbg(dev, "new firmware file version is later\n"); is_later = true; @@ -821,6 +848,7 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, dev_dbg(dev, "new firmware file version is same or earlier\n"); } +not_supported_version: not_signed_fw: release_firmware(fw); return is_later; From patchwork Fri Jan 18 01:13:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10769271 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 05DD7139A for ; Fri, 18 Jan 2019 01:13:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E21AD286D4 for ; Fri, 18 Jan 2019 01:13:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D3DED28751; Fri, 18 Jan 2019 01:13:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0D071286D4 for ; Fri, 18 Jan 2019 01:13:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726411AbfARBNy (ORCPT ); Thu, 17 Jan 2019 20:13:54 -0500 Received: from hqemgate15.nvidia.com ([216.228.121.64]:11381 "EHLO hqemgate15.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726182AbfARBNy (ORCPT ); Thu, 17 Jan 2019 20:13:54 -0500 Received: from hqpgpgate101.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 17 Jan 2019 17:13:30 -0800 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate101.nvidia.com (PGP Universal service); Thu, 17 Jan 2019 17:13:51 -0800 X-PGP-Universal: processed; by hqpgpgate101.nvidia.com on Thu, 17 Jan 2019 17:13:51 -0800 Received: from ajayg.nvidia.com (172.17.174.172) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 18 Jan 2019 01:13:49 +0000 From: Ajay Gupta To: CC: , Ajay Gupta Subject: [PATCH 7/7] usb: typec: ucsi: add firmware flashing support Date: Thu, 17 Jan 2019 17:13:33 -0800 Message-ID: <20190118011333.16301-1-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 X-NVConfidentiality: public MIME-Version: 1.0 X-Originating-IP: [172.17.174.172] X-ClientProxiedBy: DRBGMAIL101.nvidia.com (10.18.16.20) To HQMAIL101.nvidia.com (172.20.187.10) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1547774010; bh=w8BnzdA7X+NEdJShnpnE9RqSAOvtpUvZ0pUHvz45NsY=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: X-NVConfidentiality:MIME-Version:X-Originating-IP: X-ClientProxiedBy:Content-Type; b=USL1baTmESASUbHwXw4CsgMeagl7kUpGw51jhdzNRxcW3WNZAu1xIShbCCCuKt3Q1 w2NRXX+kkismtjh4rS0jqKe7pfPJJo1e1nipaEULKVFqCvoM8cZ3qDN1aNmA74bEt1 JO+XJDu1zJTL9m9oVrAk1zFp9XJ16gduRQOzpN5/m0/o3bzE4Yg1yIT1od2d0b6Fb0 f2Ta8ZdXrnkYC0hUP9j0zRnQfGWiNcIiPbxz3VGu97xuU7MmPVsFEToHqS/yKRY6ZT 3cE/uVMhgwACmHjpT3Ds2dv97nGdVNa9/4CsqsMW+dK5SyODNS3qKkr3NluAOg3aY7 KoSWSjtFe/EfA== Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP CCGx has two copies of the firmware in addition to the bootloader. If the device is running FW1, FW2 can be updated with the new version. Dual firmware mode allows the CCG device to stay in a PD contract and support USB PD and Type-C functionality while a firmware update is in progress. Signed-off-by: Ajay Gupta --- drivers/usb/typec/ucsi/ucsi_ccg.c | 283 ++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 1aa6ede764b5..da83c145a392 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -239,6 +239,8 @@ struct ucsi_ccg { struct ccg_resp dev_resp; u8 cmd_resp; int port_num; + int irq; + struct work_struct work; struct mutex lock; /* to sync between user and driver thread */ }; @@ -904,6 +906,276 @@ static int ccg_fw_update_needed(struct ucsi_ccg *uc, return 0; } +static int do_flash(struct ucsi_ccg *uc, enum enum_flash_mode mode) +{ + struct device *dev = uc->dev; + const struct firmware *fw = NULL; + const char *p, *s; + const char *eof; + int err, row, len, line_sz, line_cnt = 0; + unsigned long start_time = jiffies; + struct fw_config_table fw_cfg; + u8 fw_cfg_sig[FW_CFG_TABLE_SIG_SIZE]; + u8 *wr_buf; + + err = request_firmware(&fw, ccg_fw_names[mode], dev); + if (err) { + dev_err(dev, "request %s failed err=%d\n", + ccg_fw_names[mode], err); + return err; + } + + if (uc->info.fw_mode == FW2) { + err = ccg_cmd_port_control(uc, false); + if (err < 0) + goto release_fw; + err = ccg_cmd_jump_boot_mode(uc, 0); + if (err < 0) + goto release_fw; + } + + eof = fw->data + fw->size; + + /* + * check if signed fw + * last part of fw image is fw cfg table and signature + */ + if (fw->size < sizeof(fw_cfg) + sizeof(fw_cfg_sig)) + goto not_signed_fw; + + memcpy((uint8_t *)&fw_cfg, fw->data + fw->size - + sizeof(fw_cfg) - sizeof(fw_cfg_sig), sizeof(fw_cfg)); + + if (fw_cfg.identity != ('F' | ('W' << 8) | ('C' << 16) | ('T' << 24))) { + dev_info(dev, "not a signed image\n"); + goto not_signed_fw; + } + eof = fw->data + fw->size - sizeof(fw_cfg) - sizeof(fw_cfg_sig); + + memcpy((uint8_t *)&fw_cfg_sig, + fw->data + fw->size - sizeof(fw_cfg_sig), sizeof(fw_cfg_sig)); + + /* flash fw config table and signature first */ + err = ccg_cmd_write_flash_row(uc, 0, (u8 *)&fw_cfg, + FLASH_FWCT1_WR_CMD); + if (err) + goto release_fw; + + err = ccg_cmd_write_flash_row(uc, 0, (u8 *)&fw_cfg + CCG4_ROW_SIZE, + FLASH_FWCT2_WR_CMD); + if (err) + goto release_fw; + + err = ccg_cmd_write_flash_row(uc, 0, &fw_cfg_sig, + FLASH_FWCT_SIG_WR_CMD); + if (err) + goto release_fw; + +not_signed_fw: + wr_buf = kzalloc(CCG4_ROW_SIZE + 4, GFP_KERNEL); + if (!wr_buf) + return -ENOMEM; + + err = ccg_cmd_enter_flashing(uc); + if (err) + goto release_mem; + + /***************************************************************** + * CCG firmware image (.cyacd) file line format + * + * :00rrrrllll[dd....]cc/r/n + * + * :00 header + * rrrr is row number to flash (4 char) + * llll is data len to flash (4 char) + * dd is a data field represents one byte of data (512 char) + * cc is checksum (2 char) + * \r\n newline + * + * Total length: 3 + 4 + 4 + 512 + 2 + 2 = 527 + * + *****************************************************************/ + + p = strchr(fw->data, ':'); + while (p < eof) { + s = strnchr(p + 1, CYACD_LINE_SIZE, ':'); + + if (!s) + s = eof; + + line_sz = s - p; + + if (line_sz != CYACD_LINE_SIZE) { + dev_err(dev, "Bad FW format line_sz=%d\n", line_sz); + err = -EINVAL; + goto release_mem; + } + + if (hex2bin(wr_buf, p + 3, CCG4_ROW_SIZE + 4)) { + err = -EINVAL; + goto release_mem; + } + + row = (wr_buf[0] << 8) + wr_buf[1]; + len = (wr_buf[2] << 8) + wr_buf[3]; + + if (len != CCG4_ROW_SIZE) { + err = -EINVAL; + goto release_mem; + } + + err = ccg_cmd_write_flash_row(uc, row, wr_buf + 4, + FLASH_WR_CMD); + if (err) + goto release_mem; + + line_cnt++; + p = s; + } + + dev_info(dev, "total %d row flashed. time: %dms\n", + line_cnt, jiffies_to_msecs(jiffies - start_time)); + + err = ccg_cmd_validate_fw(uc, (mode == PRIMARY) ? FW2 : FW1); + if (err) + dev_err(dev, "%s validation failed err=%d\n", + (mode == PRIMARY) ? "FW2" : "FW1", err); + else + dev_info(dev, "%s validated\n", + (mode == PRIMARY) ? "FW2" : "FW1"); + + err = ccg_cmd_port_control(uc, false); + if (err < 0) + goto release_mem; + + err = ccg_cmd_reset(uc, mode == SECONDARY); + if (err < 0) + goto release_mem; + + err = ccg_cmd_port_control(uc, true); + if (err < 0) + goto release_mem; + +release_mem: + kfree(wr_buf); + +release_fw: + release_firmware(fw); + return err; +} + +/******************************************************************************* + * CCG4 has two copies of the firmware in addition to the bootloader. + * If the device is running FW1, FW2 can be updated with the new version. + * Dual firmware mode allows the CCG device to stay in a PD contract and support + * USB PD and Type-C functionality while a firmware update is in progress. + ******************************************************************************/ +static int ccg_fw_update(struct ucsi_ccg *uc, enum enum_flash_mode flash_mode) +{ + int err; + + while (flash_mode != FLASH_NOT_NEEDED) { + err = do_flash(uc, flash_mode); + if (err < 0) + return err; + err = ccg_fw_update_needed(uc, &flash_mode); + if (err < 0) + return err; + } + dev_info(uc->dev, "CCG FW update successful\n"); + + return err; +} + +static int ccg_restart(struct ucsi_ccg *uc) +{ + struct device *dev = uc->dev; + int status; + + status = ucsi_ccg_init(uc); + if (status < 0) { + dev_err(dev, "ucsi_ccg_start fail, err=%d\n", status); + return status; + } + + status = devm_request_threaded_irq(dev, uc->irq, NULL, ccg_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + dev_name(dev), uc); + if (status < 0) { + dev_err(dev, "request_threaded_irq failed - %d\n", status); + return status; + } + + uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); + if (IS_ERR(uc->ucsi)) { + dev_err(uc->dev, "ucsi_register_ppm failed\n"); + return PTR_ERR(uc->ucsi); + } + + return 0; +} + +static void ccg_update_firmware(struct work_struct *work) +{ + struct ucsi_ccg *uc = container_of(work, struct ucsi_ccg, work); + enum enum_flash_mode flash_mode; + int status; + + status = ccg_fw_update_needed(uc, &flash_mode); + if (status < 0) + return; + + if (flash_mode != FLASH_NOT_NEEDED) { + ucsi_unregister_ppm(uc->ucsi); + if (uc->irq) + devm_free_irq(uc->dev, uc->irq, uc); + + ccg_fw_update(uc, flash_mode); + ccg_restart(uc); + } +} + +static ssize_t do_flash_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + struct i2c_client *i2c_cl = to_i2c_client(dev); + struct ucsi_ccg *uc = i2c_get_clientdata(i2c_cl); + unsigned int mode; + + if (kstrtouint(buf, 10, &mode)) + return -EINVAL; + + if (mode) + schedule_work(&uc->work); + + return n; +} + +static ssize_t do_flash_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "[Usage]\n" + "1) copy ccg_boot.cyacd /lib/firmware/\n" + "2) copy ccg_1.cyacd /lib/firmware/\n" + "3) copy ccg_2.cyacd /lib/firmware/\n" + "4) echo 1 > do_flash\n" + "5) Remove all TypeC cable/adapter after flashing\n"); +} + +static DEVICE_ATTR_RW(do_flash); + +static struct attribute * +ucsi_ccg_sysfs_attrs[] = { + &dev_attr_do_flash.attr, + NULL, +}; + +static struct attribute_group +ucsi_ccg_attr_group = { + .attrs = ucsi_ccg_sysfs_attrs, +}; + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -924,6 +1196,8 @@ static int ucsi_ccg_probe(struct i2c_client *client, uc->ppm.sync = ucsi_ccg_sync; uc->dev = dev; uc->client = client; + mutex_init(&uc->lock); + INIT_WORK(&uc->work, ccg_update_firmware); /* reset ccg device and initialize ucsi */ status = ucsi_ccg_init(uc); @@ -952,6 +1226,8 @@ static int ucsi_ccg_probe(struct i2c_client *client, return status; } + uc->irq = client->irq; + uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); if (IS_ERR(uc->ucsi)) { dev_err(uc->dev, "ucsi_register_ppm failed\n"); @@ -968,6 +1244,11 @@ static int ucsi_ccg_probe(struct i2c_client *client, } i2c_set_clientdata(client, uc); + + status = sysfs_create_group(&uc->dev->kobj, &ucsi_ccg_attr_group); + if (status) + dev_err(uc->dev, "cannot create sysfs group: %d\n", status); + return 0; } @@ -975,7 +1256,9 @@ static int ucsi_ccg_remove(struct i2c_client *client) { struct ucsi_ccg *uc = i2c_get_clientdata(client); + cancel_work_sync(&uc->work); ucsi_unregister_ppm(uc->ucsi); + sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group); return 0; }