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) {