From patchwork Mon Jan 28 20:37:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ajay Gupta X-Patchwork-Id: 10784709 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 1B647922 for ; Mon, 28 Jan 2019 20:37:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0B2782C048 for ; Mon, 28 Jan 2019 20:37:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F3A5B2C35B; Mon, 28 Jan 2019 20:37:48 +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 541DB2C048 for ; Mon, 28 Jan 2019 20:37:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727766AbfA1Uhr (ORCPT ); Mon, 28 Jan 2019 15:37:47 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:34111 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727115AbfA1Uhq (ORCPT ); Mon, 28 Jan 2019 15:37:46 -0500 Received: by mail-pg1-f194.google.com with SMTP id j10so7725018pga.1 for ; Mon, 28 Jan 2019 12:37:45 -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=syDpRKg2EbZnqmLDx7nb4agewOZ8WED9GVHBglxsS1A=; b=j+J/+ZrqW6wpMGttXUbl7g9DLaEkrSBvzl2uu5SPFnOzvRXUacRHeY8Q78tNSg+xIV 3OYUed/yUTVRQjPUQlDChfAUBZ+7GIm0+kONVjHUyXbwqOCQgQgw24yjFLk7TLDBdL+z Ti3gyeEZBQwAwlPXLD1gFfW04R9Ry2QWSvV3CQ+evWyc+LslSQOsyPVVsG00KhTer+Nh SbPqfUWFpE/dXhklI5WhIwAbL9lbTj55ybk3rU8EBo9u90D6Xv0MnA6B3zJS0q1IgXU8 ERqWwEOU66G4Zfcb27rCIoUSQAM4sZQwOfDbIgJavqHXiYd7PwfCcpdEQdwf77mdHvlT GnuA== 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=syDpRKg2EbZnqmLDx7nb4agewOZ8WED9GVHBglxsS1A=; b=rydPOgvwpAjJ9OWCe9b0HFj520TG8Rvq3WjEWAghPaz9LqUYCiqV6Wsh7dH6wga6ie LIW4rh53NsST0o1C2rXW5Zj9wIYGNyboF9vu5ahN7VXk5x9ahGAQCti1k3DLrhVaHT8a fF1iiDY2Z+7b98lXfod45bD1NvxPozHWHdkfmN7NDGiuOVEchGKMwATsza3MfiSTQdTj 91YMqSywuW6Shy09Ui37LEC/jWSRlvuL8Rkji+XWLmxJLhkysN1Zzyo2bGKh8n4YBgZq +k6MfrlaEXkJi6kl4sh0Qh6JguHxZ81xps4UaZkrbC7HvCcyiOxPuFfFTRPg8d6Psc3i EzcA== X-Gm-Message-State: AJcUukdve+heETrppW3zE28xzTNzgXnbYRTrJF7Tm7lEZM4KKxMP44SQ xsJ0mukhVEwCGDW8xukOb3I= X-Google-Smtp-Source: ALg8bN6AO+8WgA5M0o+CL/u7A31e9zkeqsRkjT1mZ5yGWx3H3EP50KOM7UTSqRMEDDo2p6D8DsyEkw== X-Received: by 2002:a62:130c:: with SMTP id b12mr23425195pfj.247.1548707865424; Mon, 28 Jan 2019 12:37:45 -0800 (PST) Received: from ajayg.nvidia.com (searspoint.nvidia.com. [216.228.112.21]) by smtp.gmail.com with ESMTPSA id t3sm34628047pgv.31.2019.01.28.12.37.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 28 Jan 2019 12:37:44 -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 v2 4/6] usb: typec: ucsi: add cmd used for fw flashing Date: Mon, 28 Jan 2019 12:37:29 -0800 Message-Id: <20190128203731.12681-5-ajayg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190128203731.12681-1-ajayg@nvidia.com> References: <20190128203731.12681-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 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 v1: - Updated commit message - Used mask and shift instead of bit fields 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 f71387a21693..b1fadec9172b 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 { #define CCG_DEVINFO_FWMODE_SHIFT (0) #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) @@ -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) @@ -493,6 +522,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) {