From patchwork Sat Feb 2 01:05: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: 10793909 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 6950817E9 for ; Sat, 2 Feb 2019 01:05:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5ACF232F9F for ; Sat, 2 Feb 2019 01:05:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4F53B32FA0; Sat, 2 Feb 2019 01:05:25 +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,FREEMAIL_FROM,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 BB4EE32F9D for ; Sat, 2 Feb 2019 01:05:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727100AbfBBBFY (ORCPT ); Fri, 1 Feb 2019 20:05:24 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:42426 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726591AbfBBBFY (ORCPT ); Fri, 1 Feb 2019 20:05:24 -0500 Received: by mail-pg1-f194.google.com with SMTP id d72so3720925pga.9 for ; Fri, 01 Feb 2019 17:05:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jLStiT4BRse05XQf1t9oNBMChtzLA8+f5xlAxVPrtx8=; b=ikwoLDuWedprcpZBz74Bs8lr55iRTplej5S+wBzEu2pdn7z+W9Vg4pfDzDeVlL+AHO TpdOvHfQ3OKsyMEFvyM73DZWkaXHLLtXOCQEga5hnbZger1MDh1CVDUCzImXO6gYEOJx DSeMbimPp+GW6DeQR2daIW1FAl0S0WbLJE7p9lBCnlkCtfjx6nVPJ4yd7wMH9kj/Towz /Y1DWQ37l6KaCeDAAdHxl6DF6AF0UfZU9p/AN6rPkPHTUreSM5wdL3QPLFEzkvRWAavw GZVpF1tW+jjKokTqXRJRjoww5pDFTmihqvn2ZBr/ii8aPcMGgoh2afzbeVRIkc2jNK/r hjnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jLStiT4BRse05XQf1t9oNBMChtzLA8+f5xlAxVPrtx8=; b=cwW0vnXC7cA5dhrcrAiX9VKWcs7bazvWJfDApFkzyO57rShsb6uP4voLOjCJp7ApwZ IXZrwbiOq/fhuSfNXcfiU/ksIinMVbOWdphNAYFyovRL232KZa06uqJTJH01CM5B61N8 Y+cE3A/ddpu4vLcwFR7GehwXOuTf1J3iHwGmFdvbL00euL5mo0sqQfjthe18HoPNbGHb KhceBCLHrtGrMQFw9cbkg2LqlmCsgWWFH/tey+07W/HQTmwjCRpCA2zruIKTDgeC823t I0G6cXcW9MAf2V0Wgx0iGGiQe2ZToMircCPQVyVR2mGyv/5R1mWvy2a9wRfaL8+2ELdS L4+w== X-Gm-Message-State: AHQUAuYE07WnZ3+q2M3pPBgGUs1aJc/a6qvIvnqiyak5C+zZUtRSH9Za bFvaJzGuFn18WVD5FVfNOlwhThjA X-Google-Smtp-Source: AHgI3IbhN5VUVKBvPAVclN8zWX0Le0p/XD1cymzH5Os0QQCFvqx93T5c5rYZPJxaixyCgT60zVjhJQ== X-Received: by 2002:a63:f844:: with SMTP id v4mr4403349pgj.82.1549069521963; Fri, 01 Feb 2019 17:05:21 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:21 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 1/6] usb: typec: ucsi: add get_fw_info function Date: Fri, 1 Feb 2019 17:05:05 -0800 Message-Id: <20190202010510.25016-2-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta Function is to get the details of ccg firmware and device version. It will be useful in debugging and also during firmware update. Signed-off-by: Ajay Gupta --- Changes from v2 to v3 - Fixed comments from Greg on using __le16 and __packed - Added enum_fw_mode and changed version[3] to version[FW2 + 1] drivers/usb/typec/ucsi/ucsi_ccg.c | 66 ++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index de8a43bdff68..3884fb41c72e 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -17,15 +17,54 @@ #include #include "ucsi.h" +enum enum_fw_mode { + BOOT, /* bootloader */ + FW1, /* FW partition-1 (contains secondary fw) */ + FW2, /* FW partition-2 (contains primary fw) */ + FW_INVALID, +}; + +struct ccg_dev_info { +#define CCG_DEVINFO_FWMODE_SHIFT (0) +#define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) +#define CCG_DEVINFO_PDPORTS_SHIFT (2) +#define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT) + u8 mode; + u8 bl_mode; + __le16 silicon_id; + __le16 bl_last_row; +} __packed; + +struct version_format { + __le16 build; + u8 patch; + u8 ver; +#define CCG_VERSION_MIN_SHIFT (0) +#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT) +#define CCG_VERSION_MAJ_SHIFT (4) +#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT) +} __packed; + +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; + /* version info for boot, primary and secondary */ + struct version_info version[FW2 + 1]; }; -#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 +259,23 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int get_fw_info(struct ucsi_ccg *uc) +{ + int err; + + err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version), + sizeof(uc->version)); + if (err < 0) + return err; + + err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), + sizeof(uc->info)); + if (err < 0) + return err; + + return 0; +} + static int ucsi_ccg_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -248,6 +304,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 Sat Feb 2 01:05: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: 10793911 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 0ACE2184E for ; Sat, 2 Feb 2019 01:05:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F07E632F9D for ; Sat, 2 Feb 2019 01:05:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E542332FA0; Sat, 2 Feb 2019 01:05:25 +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,FREEMAIL_FROM,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 594FA32F9D for ; Sat, 2 Feb 2019 01:05:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727101AbfBBBFY (ORCPT ); Fri, 1 Feb 2019 20:05:24 -0500 Received: from mail-pl1-f195.google.com ([209.85.214.195]:36029 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726742AbfBBBFY (ORCPT ); Fri, 1 Feb 2019 20:05:24 -0500 Received: by mail-pl1-f195.google.com with SMTP id g9so4083034plo.3 for ; Fri, 01 Feb 2019 17:05:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=UwTJ4YoHcO9gOD4+eevDPZ4QEdT5/1P8hF7JTltl0QM=; b=Jo1kMXrcLYCclVCGNP64CXjxcnxBJzLwxYf+UB4Y3JoeGn4/ILaDYS9goQV21lJC/X LXWlBwuBEA4YcqBEQg2nDZv2SdI57H2z5ihXCDwDLOyL0u+TU6u/Z1zl/fLcGO3/SJiC 5fqD1i4u/S3Xv+GYKjMaYzBp4ItgpaWRIwqYyf4Q2EoTa5F5Bm8Xryv+yi+nvXbH/JJ/ LgSgyscJlxJlJXx8l8FiZbRO57fPc8ggYFgnpBGhmcDP8M0CpzXVHvp+5ZXnageZA/Wb rncMceKqFuxasUyxBUZ0gmvM9RD7icmteFsfn2h2awoDyjp4cngS729705mqPQZ2JQ9j orWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=UwTJ4YoHcO9gOD4+eevDPZ4QEdT5/1P8hF7JTltl0QM=; b=a+9LMIIp8O4Kb4bMGFLSP07HvfvE1PiyE1J0myhzohgJxejcdqogFZxi60A0igkRDF bMq2b4cND5yj70CHw/jpS+kvmRzAf1RXxonzjeJv5bHSr7yu1gnFex0816ZaGrYIT5SA 1Fn2XsQhk+npGRmop0PoelYrFsQbyAg+CMLtrCIWW/Jy11Bp0uV5EO7kjzeHW8HnSjHr qPpSqARdlmxvUNW0p+tE88+FQI1sSceMz26oKOWgxALHz6yVXZscjhJWp/pNPptcZ7sN 8YTv/mOca+H/FBceAMfUh4ZbGTsA11a8EKiV/y88BOV26kf296Fpoj07aLfs/x7YtQeM 9Rlg== X-Gm-Message-State: AJcUukfPN8ccSGxs87JXIdk2xY058gGp1K7MT0keW8qUYzeDFnwTJjAA Q4++VLxrTzHldxaTi5s+pps= X-Google-Smtp-Source: ALg8bN7FO977ni11tgYzplZjucsZCDrGNQf0OgFTMdjzumzsdxI0kboDZ3IfFk4IByCMlljmL7/2sw== X-Received: by 2002:a17:902:5a5:: with SMTP id f34mr42158386plf.161.1549069523065; Fri, 01 Feb 2019 17:05:23 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:22 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 2/6] usb: typec: ucsi: add ccg command framework Date: Fri, 1 Feb 2019 17:05:06 -0800 Message-Id: <20190202010510.25016-3-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta Used to send various commands to ccg controller. They are mainly used during firmware update process. We wait for response after sending the command and then read the response from RAB_RESPONSE register. Signed-off-by: Ajay Gupta --- Changes from v2 to v3 - Removed unused structures - Used CCG_EVENT_MAX instead of long structure and sizeof() drivers/usb/typec/ucsi/ucsi_ccg.c | 172 ++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 9 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 3884fb41c72e..58b697d1ef8b 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -24,6 +24,29 @@ enum enum_fw_mode { FW_INVALID, }; +#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 { #define CCG_DEVINFO_FWMODE_SHIFT (0) #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) @@ -50,6 +73,36 @@ 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, +}; + +#define CCG_EVENT_MAX (EVENT_INDEX + 43) + +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; @@ -58,17 +111,14 @@ struct ucsi_ccg { struct ccg_dev_info info; /* version info for boot, primary and secondary */ struct version_info version[FW2 + 1]; + /* 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; @@ -276,6 +326,110 @@ static int get_fw_info(struct ucsi_ccg *uc) return 0; } +static inline bool invalid_async_evt(int code) +{ + return (code >= CCG_EVENT_MAX) || (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; + get_fw_info(uc); + } + if (invalid_async_evt(uc->dev_resp.code)) + dev_err(dev, "invalid async 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; + + 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; + + 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 Sat Feb 2 01:05:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10793913 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 DF77B13BF for ; Sat, 2 Feb 2019 01:05:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D313832F9D for ; Sat, 2 Feb 2019 01:05:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C7BCB32FA2; Sat, 2 Feb 2019 01:05:27 +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,FREEMAIL_FROM,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 B7CE732F9D for ; Sat, 2 Feb 2019 01:05:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727181AbfBBBF0 (ORCPT ); Fri, 1 Feb 2019 20:05:26 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:37272 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726742AbfBBBFZ (ORCPT ); Fri, 1 Feb 2019 20:05:25 -0500 Received: by mail-pl1-f196.google.com with SMTP id b5so4078418plr.4 for ; Fri, 01 Feb 2019 17:05:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Dw5XvpHxxvWb9lyvFcCghubZUcX0UpsvFTAHbMA8ty8=; b=Q8EmueDkhBUtdLJGtknjWHeCBe56TEUdrO4YnQMKqSzVXVw9UPSQ+JXSgL+x/Dgric FgcETqZQvHiSIk1iauZkLrVBl6uLl/XxOGoA8kHqyTSRnB9IVCFbtRnCOc8osZNSpK2x h6o4Qh9ZLWkeRXrLeeaWvBaebiiAbGznSJjzVmXk0zVoI3tFtEm7WqZKk6VwwZjltEuf UIayNAupALSwTxUFbKromhxP1Mm7MsaaI+aWtUIxwUPsGA13BZ4R/hE2SPwUa4D8DPbN nEU40vm+K7RDQ3lSMUj33VLyjwZOnBG+iVj2jUfUEzQ1o3tToTGvsaXIeqviq26S/f1j MUPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Dw5XvpHxxvWb9lyvFcCghubZUcX0UpsvFTAHbMA8ty8=; b=tOg0dYfojpV6nfWlw7ZupGk8c8I1ZBEMNF9vSwhenNxIFQv2gDt0PrK4aGowVCjzIW 3KVk8GLBHtugmcxOshHkllqDMUz6z+ZD9IzI+KZ6GxlH0RZyn9S3Qk8eY62TuxcMxTzb lOsiQoXRTqFCKelp25K+0KxhEaDptXngBONwPLZUmARvsQIifY3gQN0iXxdKYzc1RONT HZNPqrdjIwvd0nGTSJQMpczDi6PoRXJAcNVSNuhJy3GUUzzwUkPljfhTT+HhcHXFwyqG PEWMbeLS2KUTOgfIDBXSnihYzrLf8HLATwboOWsiNwL8HlXYzHTTj7AtBQkVp1e4DsXF py8A== X-Gm-Message-State: AJcUukfsMeshXdgOimdmrxmekHyTYYwFpAWeprT/jNJ0V3AGjhNtP1B7 WZNEOv0+FrH7XzKwlzDLc919NNcr X-Google-Smtp-Source: ALg8bN66989wmJoRi3/WT0TpPlaEnadbqaXQ4iqcm0IXradbvGU6ehRSNwOFO/AyrC9wQWpUf1Yc2g== X-Received: by 2002:a17:902:2a66:: with SMTP id i93mr41314677plb.113.1549069524176; Fri, 01 Feb 2019 17:05:24 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:23 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 3/6] usb: typec: ucsi: add port num info Date: Fri, 1 Feb 2019 17:05:07 -0800 Message-Id: <20190202010510.25016-4-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta Read PD port number information and save. It will be required while sending PD_PORT_ENABLE command. Signed-off-by: Ajay Gupta --- Changes from v2 to v3 - Fixed comments from Heikki on removing SHIFT 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 58b697d1ef8b..63b07b7d17f2 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -117,6 +117,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) @@ -464,6 +465,11 @@ static int ucsi_ccg_probe(struct i2c_client *client, return status; } + uc->port_num = 1; + + if (uc->info.mode & CCG_DEVINFO_PDPORTS_MASK) + uc->port_num++; + status = devm_request_threaded_irq(dev, client->irq, NULL, ccg_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, From patchwork Sat Feb 2 01:05:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10793915 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 19525184E for ; Sat, 2 Feb 2019 01:05:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0AC4C32F9D for ; Sat, 2 Feb 2019 01:05:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F3B9332FA0; Sat, 2 Feb 2019 01:05:27 +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,FREEMAIL_FROM,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 5C22032F9F for ; Sat, 2 Feb 2019 01:05:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727202AbfBBBF0 (ORCPT ); Fri, 1 Feb 2019 20:05:26 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:37274 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727154AbfBBBF0 (ORCPT ); Fri, 1 Feb 2019 20:05:26 -0500 Received: by mail-pl1-f196.google.com with SMTP id b5so4078439plr.4 for ; Fri, 01 Feb 2019 17:05:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6T+VlfYfzQBDVcCATmfdWfBzG/0ZHJEWYZgK0joCQ9I=; b=IrYP+Ob3ieS2nFciwY/Oe51ucN7C4qzNdHFvctb4FQKefA434vbH0KDDhWxRL/4cLl 1gwuQZEbJgbaV1za733JglsxhYVoUELoYVxU8Qx79wVDoXmiWBxELkIVdohKh1O90cFZ jyTU+WnjnEsX5mCBdJriSYj+JW+gj0EaYI9H+TvKyVKGgCD7l5IO0ZCwp+0IuNv+EhKp CpRsMTUjnFnErZZN1C4+7ay+pP+F/8+UrJQrvg8Hw8fZZHo0n1wvjr9upzcmWkT6wYTM UciyXs1NLmcZW12ym41Dw/mCviAerSj6G1LGL8fPBb4E4anRjdEq++DXKg4MS8VrsjEY Wcew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6T+VlfYfzQBDVcCATmfdWfBzG/0ZHJEWYZgK0joCQ9I=; b=k7pRCt0w3DkOISmmtN+e6kaukx7kYdvQaD/aU+yG89gmi4347k2LYvmgYvQ8Uho4b4 P82pZaKCdXaSmgzZue2rIBWGznsuW8/yF3UqmeWc3dvl5iP4keCME/yHiwdKiT7pPjSh Cu7x38uYCy+8O6GFFLKk9IcTbNfedDimh6bFpQtGGDeZBjLwjxn3tzHMd3QEQQ91gVrr dtvqaYZYmsujXY58uzoHGPhPUQc6PuLzy+JiYgjApo+BcSxe4KQQShjad30DcIV8Fqba IWVAKWjzy+sLcxLeDv3grSV/YA6JzvCELHR4vxJ/ILAhjROwgLRTjud5RdLNYAtcOlrs WfcQ== X-Gm-Message-State: AJcUukeiCPqVg9p1nQ09VJzHyP7tjRmlVi6STiiSWxNBcZxdTDS9UW/v m5xcgJEPAyRGLC+tr9Jt6V8= X-Google-Smtp-Source: ALg8bN5FGN4Iu5fEZokfWLz/uKn2YJ0N5RJKWth8ZQm3ZU3nAeupvto6g7x308R11m/BvhIskbbT2A== X-Received: by 2002:a17:902:850c:: with SMTP id bj12mr41238228plb.46.1549069525264; Fri, 01 Feb 2019 17:05:25 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:24 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 4/6] usb: typec: ucsi: add cmd used for fw flashing Date: Fri, 1 Feb 2019 17:05:08 -0800 Message-Id: <20190202010510.25016-5-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta Adding support for below commands which will be used during firmware flashing. - ENTER_FLASHING - RESET - PDPORT_ENABLE - JUMP_TO_BOOT - FLASH_ROW_RW - VALIDATE_FW I command specific mutex lock is also added to sync between driver and user threads. Signed-off-by: Ajay Gupta --- Changes from v2 to v3 - None 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 63b07b7d17f2..b9bbe90bdf57 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -30,13 +30,34 @@ enum enum_fw_mode { #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) @@ -47,6 +68,13 @@ enum enum_fw_mode { #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 { #define CCG_DEVINFO_FWMODE_SHIFT (0) #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) @@ -118,6 +146,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) @@ -431,6 +460,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 Sat Feb 2 01:05:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10793917 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 ECA7513BF for ; Sat, 2 Feb 2019 01:05:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DCB4832F9D for ; Sat, 2 Feb 2019 01:05:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D146832FA0; Sat, 2 Feb 2019 01:05: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,FREEMAIL_FROM,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 A00EA32F9D for ; Sat, 2 Feb 2019 01:05:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727213AbfBBBF2 (ORCPT ); Fri, 1 Feb 2019 20:05:28 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:39092 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727154AbfBBBF1 (ORCPT ); Fri, 1 Feb 2019 20:05:27 -0500 Received: by mail-pl1-f196.google.com with SMTP id 101so4070776pld.6 for ; Fri, 01 Feb 2019 17:05:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JiDynt5SZQesW13SaCX+EEraV13JQPZ+sxTMFlcw8KA=; b=CxvtYJktI36w/moo+v1uWcDGVbFtgDaK8IFnP+/f5KYDIrtzui1SrIe7jWTgCBo3ck QvkE+Vrup8cfKO2N+LWB0nMlUxNyuHd9JX+YFPCvK2rtvudBaSg+lgAXi447oGTuyiCi +c56l/pa+SUfh9I9vBtTisuU2+8dT69OwHy/nemVLYBJwuBoUKtd4Bf0PEEcbZK5hF0A jcedaRhMJZFjnoAQRlZ+LjGr4bdh1z/OXHL5bWTpZrmcUWrrFrnMLpVUDejF/++wV/sT 98JgOIoUizwYlycUvn+ZLOjrRxficK/oQ33f3a2zhEI5ttBsFqn52uAQR3iWEkJw/k/l MZCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JiDynt5SZQesW13SaCX+EEraV13JQPZ+sxTMFlcw8KA=; b=DU1RB+rxyPGVZv/AzJtM6xcTtKQmgDU1O3ZQs5msleQzwqyWTBNPdCTqtRhbEK26rC hBJoNsPBryVKv3GITv+39qQC/x2bmqiB6BlyWKc8WX4o/x3bzTFUDTWYURKfkgjrCzbO WIG/PRrQWs3sMPyr4Hvp8APl9TxKL/36qGylrPYPxIUj8UhjWWkeppF0B776ShIxNfxq DrZrZk8n0JRCOIdYUsPIgzyO5ZuKzyttl2pmdK7CaCrOZ7Jzk07r7VEc6o/ASbdFIeeb n+VZlVJEtAiOfTwhjzgwWgM96UBwRqpAOByJwgwtu9jJhXlxdTh276H9yVnC4jgIk7jM zu1w== X-Gm-Message-State: AJcUukcfm5/9ug7H337t2PPkXBEmcD1bJdjjDvWvy9SasMtJXj3PeGeG vdw5/LjWJqPLlA82b1JgZJhMpIZN X-Google-Smtp-Source: ALg8bN6ZOajkFcgvnKV7CCHpcPw7Z18lXssEzCQONTT6BrEPL+lPtZNtPMQnEDRfXF01YqJQnu6MRQ== X-Received: by 2002:a17:902:20c6:: with SMTP id v6mr42422050plg.156.1549069526318; Fri, 01 Feb 2019 17:05:26 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:25 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 5/6] usb: typec: ucsi: add fw update needed check Date: Fri, 1 Feb 2019 17:05:09 -0800 Message-Id: <20190202010510.25016-6-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta Here we read the currently flashed firmware version of both primary and secondary firmware and then compare it with version of firmware file to determine if flashing is required. Signed-off-by: Ajay Gupta --- Changes from v2 to v3 - Moved enum_fw_mode enum to patch [1/6] drivers/usb/typec/ucsi/ucsi_ccg.c | 146 ++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index b9bbe90bdf57..d3985a0be9f8 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 @@ -75,6 +76,22 @@ enum enum_fw_mode { #define FW2_METADATA_ROW 0x1FE #define FW_CFG_TABLE_SIG_SIZE 256 +static int secondary_fw_min_ver = 41; + +enum enum_flash_mode { + SECONDARY_BL, /* update secondary using bootloader */ + PRIMARY, /* update primary using secondary */ + SECONDARY, /* update secondary using primary */ + FLASH_NOT_NEEDED, /* update not required */ + FLASH_INVALID, +}; + +static const char * const ccg_fw_names[] = { + /* 0 */ "ccg_boot.cyacd", + /* 1 */ "ccg_primary.cyacd", + /* 2 */ "ccg_secondary.cyacd" +}; + struct ccg_dev_info { #define CCG_DEVINFO_FWMODE_SHIFT (0) #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) @@ -101,6 +118,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, @@ -647,6 +678,121 @@ 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) +{ + 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->ver << 24; + + new_version = fw_cfg.app.build | fw_cfg.app.patch << 16 | + fw_cfg.app.ver << 24; + + if (!ccg_check_vendor_version(uc, app, &fw_cfg)) + goto not_supported_version; + + if (new_version > cur_version) + is_later = true; + +not_supported_version: +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; + } + + 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 Sat Feb 2 01:05:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10793919 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 1180B13BF for ; Sat, 2 Feb 2019 01:05:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 00FC132F9D for ; Sat, 2 Feb 2019 01:05:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E9EB232FA0; Sat, 2 Feb 2019 01:05:30 +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,FREEMAIL_FROM,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 1DE5932F9D for ; Sat, 2 Feb 2019 01:05:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727321AbfBBBF3 (ORCPT ); Fri, 1 Feb 2019 20:05:29 -0500 Received: from mail-pl1-f196.google.com ([209.85.214.196]:35199 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727154AbfBBBF3 (ORCPT ); Fri, 1 Feb 2019 20:05:29 -0500 Received: by mail-pl1-f196.google.com with SMTP id p8so4084910plo.2 for ; Fri, 01 Feb 2019 17:05:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bCtJ6JFhsXnthUHgqqIviTwZ7LvvZDQ9FC4e2gKEIYs=; b=DwHDn7f4DC5Vq+I7+78qrDYrAW+2Nlev0pfGp/74IYeNbng5nJ25q2aoVnyDhaVkhX TGYHvS6eATxl3agYdkVSD6tqa2CXVrjA9GOhkyliKrUmrmbo8otu1Swaa7cMN55C3MVo u+f7QaaDrNMKejtrjkdZmUE2kmG/kX8FkYniWgRpReD4ItiSc264l/CKm1m2mnFspdtO R9m+TXqo6LwG4rkaWstRzNbHNsqxuBL4qqpwiO9oN/nHTpFrvEX/f2Yb7YzzhJRNCODr wBgiWb/7jjxfLnkWL52AdiarwwkGWjy7AM9//nFykudLq9YVXbDZ6BU0d+9NTZ1ertHo 5a1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bCtJ6JFhsXnthUHgqqIviTwZ7LvvZDQ9FC4e2gKEIYs=; b=ng6nzLa3g/SSnjU32Kd92tS0x+afaTqR5CPRrqGRR7ZxxvHFnY94ub1mYXz6Z4/Gsg EyIutiTYeYmn2N75dtLbI1S/jT4p450han67lsS+DXL0mB0Xyo2k4ocRK4xEo+JO+243 dqdH/si6RNJF4yBBqki82yNEz+PeaoB9V8PWPfG9QT2ksN0vS1U8+dSpjm9EaaRGX0pE 0lcnodhOrIPyvvChqu/SccXCNL3tWjJNBGVuDUMig5sHMj6Tkh0UGugld1jZ5WaxlMln IQMJ4YenNvi2MTnpdZFFP1cABc8fi8uuKVnWf5mPvGiUh5nVxEwh4IIstSNL9DUAZaoO 8QBg== X-Gm-Message-State: AJcUukfP8txgB1ROhHHu1qI7KxOywOLKkHlAiNvJwSLpF4GV9Sr079BM h8YgBYu4cwpFayH3HwFw0ursvElY X-Google-Smtp-Source: ALg8bN6WOCfsQ56XHJidWKX8o57i+gCAGJS5JOc6f03CztpQpL1cg6CSZWlNrMm7evTakhH1NOYIyQ== X-Received: by 2002:a17:902:2bc5:: with SMTP id l63mr42716231plb.107.1549069527508; Fri, 01 Feb 2019 17:05:27 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id f6sm13158685pfg.188.2019.02.01.17.05.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Feb 2019 17:05:26 -0800 (PST) From: Ajay Gupta X-Google-Original-From: Ajay Gupta To: heikki.krogerus@linux.intel.com Cc: linux-usb@vger.kernel.org, Ajay Gupta Subject: [PATCH v3 6/6] usb: typec: ucsi: add firmware flashing support Date: Fri, 1 Feb 2019 17:05:10 -0800 Message-Id: <20190202010510.25016-7-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190202010510.25016-1-ajayg@nvidia.com> References: <20190202010510.25016-1-ajayg@nvidia.com> X-NVConfidentiality: public 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 From: Ajay Gupta 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 --- Changes from v2 to v3 - Used request_threaded_irq instead of devm_request_threaded_irq drivers/usb/typec/ucsi/ucsi_ccg.c | 290 +++++++++++++++++++++++++++++- 1 file changed, 286 insertions(+), 4 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index d3985a0be9f8..ddbe7ad29677 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -177,6 +177,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 */ }; @@ -793,6 +795,275 @@ 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.mode & CCG_DEVINFO_FWMODE_MASK) >> + CCG_DEVINFO_FWMODE_SHIFT) == 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 = strnchr(fw->data, fw->size, ':'); + while (p < eof) { + s = strnchr(p + 1, eof - p - 1, ':'); + + 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 = request_threaded_irq(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); + free_irq(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"); +} + +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) { @@ -813,6 +1084,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); @@ -832,15 +1105,16 @@ static int ucsi_ccg_probe(struct i2c_client *client, if (uc->info.mode & CCG_DEVINFO_PDPORTS_MASK) uc->port_num++; - status = devm_request_threaded_irq(dev, client->irq, NULL, - ccg_irq_handler, - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - dev_name(dev), uc); + status = request_threaded_irq(client->irq, NULL, ccg_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + dev_name(dev), uc); if (status < 0) { dev_err(uc->dev, "request_threaded_irq failed - %d\n", status); 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"); @@ -857,6 +1131,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; } @@ -864,7 +1143,10 @@ 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); + free_irq(uc->irq, uc); + sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group); return 0; }