From patchwork Mon Jun 18 15:04:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 930975 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="m5nJzW8v"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 418ZBz49rDz9s31 for ; Tue, 19 Jun 2018 01:04:59 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964793AbeFRPE4 (ORCPT ); Mon, 18 Jun 2018 11:04:56 -0400 Received: from mail-wr0-f193.google.com ([209.85.128.193]:44891 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964787AbeFRPEy (ORCPT ); Mon, 18 Jun 2018 11:04:54 -0400 Received: by mail-wr0-f193.google.com with SMTP id x4-v6so17203012wro.11; Mon, 18 Jun 2018 08:04:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=QhSAzWIbZNv3ZYduYlvD46OU2f2p4PApqCFdJjZeWno=; b=m5nJzW8vKgb3pZ44DgG2+gf/+jbA0oOH71lsiospNP6TbPVuKWA4SCkNGuo4Y7B0Nq KiDgzmmm/2ofNRs9Xn6VX9m1RWSb5PA9WsgM0No4y81zDio9iWDmPtf3vbq9Mnte4twQ iy0uQcaqLTq8UxRILBs2/oMkmD+O2I60EsHVQ7CEYs/qiUhYB0qo1IO9HM0sp9EarBFy lYsNcXc4eYNkkuuPbLoNSIM1FjztftlSFNC1AeRefEFWqVY0uspYOaMUYcxnMpRAYUD4 py2N11lGirV0QDi9s44EPh0yfE4agqaIhWcAyyNE2uJRYL7f7fZqvUY7ttgTWsTPczpe xT6w== 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; bh=QhSAzWIbZNv3ZYduYlvD46OU2f2p4PApqCFdJjZeWno=; b=DZyueFJJH9iD4qSqWSPyEEG/UyZXa013yCMeQXPeB3cBuRG1s2DLahCqJ5kpUNVCfI dbmjuid43zw3jkrKMUeoFn1oU3BdY3gtJ+7IcqGBGJsIV8ZKFeAbm1G8+jrCuSoGkJHf pmuqmhLoiHAHL20JZvC/OreoDw0o3yAhxgkB7zi1c84n1m+PNKsl9EF9nGO2mLSLyJ8q oZslUiDlIJZfII/yyCzvGzsSNeAZBRBV7KwVhePQnF6yK096SGD2RTvb9dWo96leQ7cA EMAAp+jLTfpv2BW4nK8R05RLWE7mSERJSeIgJoBnX8uqiivThaKpU4KZEPHC//Vg+Hrd b5qw== X-Gm-Message-State: APt69E286YsYSesOPpXa60UIB7ewCVCxbux3b7Vua49CIHdq5nSgjtfR B0K4mjDtE/Er0yMVKoSlhMQ= X-Google-Smtp-Source: ADUXVKJovbbGMzEcblfc7fLsdOC4268zFybsztPOGv3/hXCBZuZMpyRgHxaz9EskuT2iMvI/B1bNLg== X-Received: by 2002:adf:aef3:: with SMTP id y106-v6mr11370309wrc.53.1529334292648; Mon, 18 Jun 2018 08:04:52 -0700 (PDT) Received: from localhost (pD9E51B80.dip0.t-ipconnect.de. [217.229.27.128]) by smtp.gmail.com with ESMTPSA id f2-v6sm17359678wre.16.2018.06.18.08.04.51 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Jun 2018 08:04:51 -0700 (PDT) From: Thierry Reding To: Wolfram Sang Cc: Laxman Dewangan , Jon Hunter , Mikko Perttunen , linux-i2c@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH] i2c: tegra: Add support for Tegra194 Date: Mon, 18 Jun 2018 17:04:50 +0200 Message-Id: <20180618150450.13723-1-thierry.reding@gmail.com> X-Mailer: git-send-email 2.17.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org From: Thierry Reding In order to support advanced features, the I2C FIFO interface was changed in the version of the Tegra I2C controller found in Tegra194. The changes are backwards incompatible, so the driver needs to be programmed in a slightly different way on new chips. Add support for MST FIFO programming and add an OF match entry for Tegra194. At the same time, mark all prior generations of this controller as not having the MST FIFO interface. Signed-off-by: Thierry Reding Acked-by: Jon Hunter --- drivers/i2c/busses/i2c-tegra.c | 99 +++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 5fccd1f1bca8..a2779e9af1ff 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -115,6 +115,18 @@ #define I2C_CONFIG_LOAD_TIMEOUT 1000000 +#define I2C_MST_FIFO_CONTROL 0x0b4 +#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0) +#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1) +#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4) +#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16) + +#define I2C_MST_FIFO_STATUS 0x0b8 +#define I2C_MST_FIFO_STATUS_RX_MASK 0xff +#define I2C_MST_FIFO_STATUS_RX_SHIFT 0 +#define I2C_MST_FIFO_STATUS_TX_MASK 0xff0000 +#define I2C_MST_FIFO_STATUS_TX_SHIFT 16 + /* * msg_end_type: The bus control which need to be send at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer. @@ -154,6 +166,7 @@ struct tegra_i2c_hw_feature { u16 clk_divisor_fast_plus_mode; bool has_multi_master_mode; bool has_slcg_override_reg; + bool has_mst_fifo; }; /** @@ -266,13 +279,24 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; - u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); + unsigned int offset; + u32 mask, val; + + if (i2c_dev->hw->has_mst_fifo) { + mask = I2C_MST_FIFO_CONTROL_TX_FLUSH | + I2C_MST_FIFO_CONTROL_RX_FLUSH; + offset = I2C_MST_FIFO_CONTROL; + } else { + mask = I2C_FIFO_CONTROL_TX_FLUSH | + I2C_FIFO_CONTROL_RX_FLUSH; + offset = I2C_FIFO_CONTROL; + } - val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; - i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + val = i2c_readl(i2c_dev, offset); + val |= mask; + i2c_writel(i2c_dev, val, offset); - while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & - (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) { + while (i2c_readl(i2c_dev, offset) & mask) { if (time_after(jiffies, timeout)) { dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); return -ETIMEDOUT; @@ -290,9 +314,15 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; - val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); - rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> - I2C_FIFO_STATUS_RX_SHIFT; + if (i2c_dev->hw->has_mst_fifo) { + val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); + rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >> + I2C_MST_FIFO_STATUS_RX_SHIFT; + } else { + val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); + rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> + I2C_FIFO_STATUS_RX_SHIFT; + } /* Rounds down to not include partial word at the end of buf */ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -321,6 +351,16 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0); i2c_dev->msg_buf_remaining = buf_remaining; i2c_dev->msg_buf = buf; + + /* + * All bytes received, mask RX_FIFO_DATA_REQ to prevent more + * interrupts from FIFO. + */ + /* + if (i2c_dev->msg_buf_remaining == 0) + tegra_i2c_mask_irq(i2c_dev, I2C_INT_RX_FIFO_DATA_REQ); + */ + return 0; } @@ -332,9 +372,15 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; - val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); - tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> - I2C_FIFO_STATUS_TX_SHIFT; + if (i2c_dev->hw->has_mst_fifo) { + val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); + tx_fifo_avail = (val & I2C_MST_FIFO_STATUS_TX_MASK) >> + I2C_MST_FIFO_STATUS_TX_SHIFT; + } else { + val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); + tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> + I2C_FIFO_STATUS_TX_SHIFT; + } /* Rounds down to not include partial word at the end of buf */ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; @@ -516,9 +562,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); } - val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | - 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; - i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + if (i2c_dev->hw->has_mst_fifo) { + val = I2C_MST_FIFO_CONTROL_TX_TRIG(8) | + I2C_MST_FIFO_CONTROL_RX_TRIG(1); + i2c_writel(i2c_dev, val, I2C_MST_FIFO_CONTROL); + } else { + val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | + 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; + i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); + } err = tegra_i2c_flush_fifos(i2c_dev); if (err) @@ -803,6 +855,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -815,6 +868,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -827,6 +881,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_config_load_reg = false, .has_multi_master_mode = false, .has_slcg_override_reg = false, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { @@ -839,6 +894,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_config_load_reg = true, .has_multi_master_mode = false, .has_slcg_override_reg = true, + .has_mst_fifo = false, }; static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { @@ -851,10 +907,25 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { .has_config_load_reg = true, .has_multi_master_mode = true, .has_slcg_override_reg = true, + .has_mst_fifo = false, +}; + +static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .has_single_clk_source = true, + .clk_divisor_hs_mode = 1, + .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, + .has_config_load_reg = true, + .has_multi_master_mode = true, + .has_slcg_override_reg = true, + .has_mst_fifo = true, }; /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, }, { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, }, { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },