From patchwork Tue Dec 24 00:58:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kunihiko Hayashi X-Patchwork-Id: 182423 Delivered-To: patch@linaro.org Received: by 2002:a92:a146:0:0:0:0:0 with SMTP id v67csp1083135ili; Mon, 23 Dec 2019 16:58:52 -0800 (PST) X-Google-Smtp-Source: APXvYqzQVmmY7xyaBw/Qrv3mMSvwT6ZVGB50g2uQipT7I1Dkgzh8KedXbN6Te6V/iRYSNulq4jJ2 X-Received: by 2002:a9d:4e92:: with SMTP id v18mr20854397otk.47.1577149131888; Mon, 23 Dec 2019 16:58:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1577149131; cv=none; d=google.com; s=arc-20160816; b=GbEA50GOM6pA4Jyv0Q8IBEDZ5nA8aV5/qs89PQ77HOoR8Ohl7OyG1fRuNEB+urvOj9 60dp0QKWE7px0/MqdzG0XaM1vKsDSDjk8YwCuzs2U9gPh5NFAmgrXyB7eVSi0obVXgDr 4l5CF8PqhgKeOZ0aqsJCvBMTs3ANpjtGx9rT3RY+exRWHTaFW6ju1GFeDFk7kvoVV8Eq CJGKAP9oehQurThBDaTcDXmzjW/xX1vY19nYPfJeKdWr2uJWEolqKbDwl67htUfqv/ff uI2Pxeuwm5Rb0BMr3sUDR7hbv3ddXk7AbgN27htHSqWcDT8nbZxZxsd589yl2dwBpReR nJJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=UKUpmCCbfic5rHOAMFlJ9IezbN7zqjhgEIN/WK0PWT8=; b=Sl6+8otwB950UlwOm0F9z+lGO4Ym3O9T5fSpoc2UMQjFBRA0X4FqQ7KvMRL/Jkoadi XUaydKmp1KI5+qIZ6yZNhkgbc9qq/uiIMePvB3Tj++iBZG5Q+35gKyDnmiKtmUDPXa2d OiTDi6SGArbbYw/SrJBevR4Ac1J/hcqysuIkRbBvv0WU66OZoMq9OebHhzS/oZYOJQTj cUGVuqOfUFoqJLz+A/RSBBTGDGHY9CqdxOsaDfvCla8Bfg06lkeUKco3W+uxXNcJCpdD tz2tGTfYS6tMSOjBOsxNUibmHzzd1kaZlMLVnGnGNEF0st80/khMhxfwPQ9BrF2tCNTf Oejw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t17si2797245oth.149.2019.12.23.16.58.51; Mon, 23 Dec 2019 16:58:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727031AbfLXA6t (ORCPT + 27 others); Mon, 23 Dec 2019 19:58:49 -0500 Received: from mx.socionext.com ([202.248.49.38]:23630 "EHLO mx.socionext.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726877AbfLXA6r (ORCPT ); Mon, 23 Dec 2019 19:58:47 -0500 Received: from unknown (HELO kinkan-ex.css.socionext.com) ([172.31.9.52]) by mx.socionext.com with ESMTP; 24 Dec 2019 09:58:46 +0900 Received: from mail.mfilter.local (m-filter-1 [10.213.24.61]) by kinkan-ex.css.socionext.com (Postfix) with ESMTP id 36DD018008B; Tue, 24 Dec 2019 09:58:46 +0900 (JST) Received: from 172.31.9.51 (172.31.9.51) by m-FILTER with ESMTP; Tue, 24 Dec 2019 09:59:25 +0900 Received: from plum.e01.socionext.com (unknown [10.213.132.32]) by kinkan.css.socionext.com (Postfix) with ESMTP id 04B7B1A01CF; Tue, 24 Dec 2019 09:58:46 +0900 (JST) From: Kunihiko Hayashi To: Mark Brown , linux-spi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Masahiro Yamada , Keiji Hayashibara , Masami Hiramatsu , Jassi Brar , Kunihiko Hayashi Subject: [PATCH 1/5] spi: uniphier: Fix FIFO threshold Date: Tue, 24 Dec 2019 09:58:23 +0900 Message-Id: <1577149107-30670-2-git-send-email-hayashi.kunihiko@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> References: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Rx threshold means the value to inform the receiver when the number of words in Rx FIFO is equal to or more than the value. Similarly, Tx threshold means the value to inform the sender when the number of words in Tx FIFO is equal to or less than the value. The controller triggers the driver to start the transfer. In case of Rx, the driver wants to detect that the specified number of words N are in Rx FIFO, so the value of Rx threshold should be N. In case of Tx, the driver wants to detect that the same number of spaces as Rx are in Tx FIFO, so the value of Tx threshold should be (FIFO size - N). For example, in order for the driver to receive at least 3 words from Rx FIFO, set 3 to Rx threshold. +-+-+-+-+-+-+-+-+ | | | | | |*|*|*| +-+-+-+-+-+-+-+-+ In order for the driver to send at least 3 words to Tx FIFO, because it needs at least 3 spaces, set 8(FIFO size) - 3 = 5 to Tx threshold. +-+-+-+-+-+-+-+-+ |*|*|*|*|*| | | | +-+-+-+-+-+-+-+-+ This adds new function uniphier_spi_set_fifo_threshold() to set threshold value to the register. And more, FIFO counts by 'words', so this renames 'fill_bytes' with 'fill_words', and fixes the calculation using bytes_per_words. Fixes: 37ffab817098 ("spi: uniphier: introduce polling mode") Cc: Keiji Hayashibara Signed-off-by: Kunihiko Hayashi --- drivers/spi/spi-uniphier.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) -- 2.7.4 diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 47cde186..ce9b301 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -290,25 +290,32 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv) } } -static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) +static void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv, + unsigned int threshold) { - unsigned int fifo_threshold, fill_bytes; u32 val; - fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, - bytes_per_word(priv->bits_per_word)); - fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); - - fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes); - - /* set fifo threshold */ val = readl(priv->base + SSI_FC); val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); - val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold); - val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold); + val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold); + val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold); writel(val, priv->base + SSI_FC); +} + +static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) +{ + unsigned int fifo_threshold, fill_words; + unsigned int bpw = bytes_per_word(priv->bits_per_word); + + fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bpw); + fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); + + uniphier_spi_set_fifo_threshold(priv, fifo_threshold); + + fill_words = fifo_threshold - + DIV_ROUND_UP(priv->rx_bytes - priv->tx_bytes, bpw); - while (fill_bytes--) + while (fill_words--) uniphier_spi_send(priv); } From patchwork Tue Dec 24 00:58:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kunihiko Hayashi X-Patchwork-Id: 182424 Delivered-To: patch@linaro.org Received: by 2002:a92:a146:0:0:0:0:0 with SMTP id v67csp1083225ili; Mon, 23 Dec 2019 16:58:58 -0800 (PST) X-Google-Smtp-Source: APXvYqySiAOmzji+UpbuOEsop9v+YwUI+HuYiE9WvgKZH2VZjNnHFyZKSqoI140UKpYNz6OmYT8U X-Received: by 2002:a9d:664a:: with SMTP id q10mr26686902otm.99.1577149136049; Mon, 23 Dec 2019 16:58:56 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1577149136; cv=none; d=google.com; s=arc-20160816; b=NTuk5f4g/6stExRO9IzdzWjM9Pv4T72ljnasCjcWKm/ImDo041c8zuuSGpzvRbKfqh 3Miah/Az03Ox1Qp94zWwCvdrwAqUO/onZbRyjhRYoFViSIs9ABQvtyw2X11DkAbRKlz8 9LNUzuAum+VRyurDuK/DMh+798glMF9qw7r3Yc6+uk3tsgtS6XEX/s5lzZDB4PDKXTvZ fDnlstYdeP5uz2lZKUYKCGlIjBIyCh8mjCHCLb4k+1gmP03oFN+pjmrylXWNYYOnUZZ5 PJNN+pxOBDHdFV+7en17yAMJdqKS+vKWIB16BuxnYtSAVYdlCHzpj/xfo3t3hj+fD+7H V7Yg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=0XoqHRTFNlIQGSRJmQYUOtnzbeRsieODrZz4Q7PUuJ4=; b=keHA2kVEr89o6g3tChxQwUlF1TRwqWHuk1XZDNTcQPNwBrQVqDEQ9Un78kbhwvTeOr 6hezc7SGgpmdyG2+N6XAa1QkNcP2cMtH5D5kQMYhe7Ah1ft1UsFvunnuU6WvUZ7jcPow hhcmdFp+/CtrcWK0SGKgHaz8r2XAG5VsV8rOT0YUm3avjxUZQqK623eRwbN2F2MuzHSE OBSF4TVMkcfpx3oHJ8E0E15bJTnOVssvBwnVCry7jcPcn7QFN2GB+2uftmlNMcpOgNfq uS8DHCyqEhByuDFZbTidYh1o2suIyPLAekhv0RVHpkHc9z9auEdZriG/Sbyq0u0LeNXa R6vg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 44si10532685otu.77.2019.12.23.16.58.55; Mon, 23 Dec 2019 16:58:56 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727121AbfLXA6v (ORCPT + 27 others); Mon, 23 Dec 2019 19:58:51 -0500 Received: from mx.socionext.com ([202.248.49.38]:23643 "EHLO mx.socionext.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727040AbfLXA6u (ORCPT ); Mon, 23 Dec 2019 19:58:50 -0500 Received: from unknown (HELO iyokan-ex.css.socionext.com) ([172.31.9.54]) by mx.socionext.com with ESMTP; 24 Dec 2019 09:58:49 +0900 Received: from mail.mfilter.local (m-filter-2 [10.213.24.62]) by iyokan-ex.css.socionext.com (Postfix) with ESMTP id 71F43603AB; Tue, 24 Dec 2019 09:58:49 +0900 (JST) Received: from 172.31.9.51 (172.31.9.51) by m-FILTER with ESMTP; Tue, 24 Dec 2019 09:59:39 +0900 Received: from plum.e01.socionext.com (unknown [10.213.132.32]) by kinkan.css.socionext.com (Postfix) with ESMTP id 126851A01CF; Tue, 24 Dec 2019 09:58:49 +0900 (JST) From: Kunihiko Hayashi To: Mark Brown , linux-spi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Masahiro Yamada , Keiji Hayashibara , Masami Hiramatsu , Jassi Brar , Kunihiko Hayashi Subject: [PATCH 4/5] spi: uniphier: Add SPI_LOOP to the capabilities Date: Tue, 24 Dec 2019 09:58:26 +0900 Message-Id: <1577149107-30670-5-git-send-email-hayashi.kunihiko@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> References: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add SPI_LOOP to the capabilities to support loopback mode. Signed-off-by: Kunihiko Hayashi --- drivers/spi/spi-uniphier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) -- 2.7.4 diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index c4e3b96..caf0446 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -543,7 +543,8 @@ static int uniphier_spi_probe(struct platform_device *pdev) master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER); master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER); - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | + SPI_LOOP; master->dev.of_node = pdev->dev.of_node; master->bus_num = pdev->id; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); From patchwork Tue Dec 24 00:58:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kunihiko Hayashi X-Patchwork-Id: 182425 Delivered-To: patch@linaro.org Received: by 2002:a92:a146:0:0:0:0:0 with SMTP id v67csp1083232ili; Mon, 23 Dec 2019 16:58:58 -0800 (PST) X-Google-Smtp-Source: APXvYqyc+18QWtgErswqPUhOUJFiUBr80W/v25t4L7yq/I0PPF+/ZbW7tMqp44oxFdk5xDBoHyYk X-Received: by 2002:a05:6830:139a:: with SMTP id d26mr36553446otq.75.1577149138609; Mon, 23 Dec 2019 16:58:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1577149138; cv=none; d=google.com; s=arc-20160816; b=nmiyI7x3L7TC55Djga1ETzkIWDZVNQYKHRXDVUSw+My/CALoppbb1AaerlHPNdX4p1 7GMixngfDhCFI3MZWQbzYdoWiDz5QSjqRAjHlxcSMO9G/DIjBqEn21iF4YxjU/MAgYq1 OkUG5ofUeCrm80iHaX0+5yQ9MW7U6ZrwvsKY2QEV3dmE7BxtAxX+YArqQoDTcth3kmg9 24WNLDRWTX0xfOR4ZoBxKPmQQN+zzeXbLPAELEyGEKrOC2/ei6X+OyNwaREA6vXeNBVg Vu1/BI1LTI5RGStNuEVCXBoCNk5PkUoX+/Mie1J0bU5BigYw4L7jYfqoXt56Vl7lzfea ErLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=DAfAuT7KGQQp8Erzb3bDfyhfWhFCtSpAEd/MKaDbA60=; b=ffT03ZdynBKI13s8m0WBy6BdfBypDwWZcJge24aw3TL2EXjBOOltU6UjdHWIvXtBRz rggsynT/9NY+5p3B16uqs6O5PlBb6YUiSObp3RiYPKp50tH60U7wdg72pYGWPJlVcIeA yRkmo8jHovFoXhG1404hCS/02trMPT3UcGliYazKQ1T+5Wnfi6pEQFt3eXTCCj71jlmS hXPn5MBkf81GVc4CwOHD1w1dyh0rxvTRziNucQraO1I3F+oKJoyaqF9ewrvznBbn/k8P XzK+upGGf+U592cIUfgs+twMkxUMUVp6HPjNJKdzhFqeEOXHoSbXP0QNxlgOSsS2RbKy eR5A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r15si8149817ota.264.2019.12.23.16.58.58; Mon, 23 Dec 2019 16:58:58 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727150AbfLXA6z (ORCPT + 27 others); Mon, 23 Dec 2019 19:58:55 -0500 Received: from mx.socionext.com ([202.248.49.38]:23638 "EHLO mx.socionext.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727071AbfLXA6x (ORCPT ); Mon, 23 Dec 2019 19:58:53 -0500 Received: from unknown (HELO kinkan-ex.css.socionext.com) ([172.31.9.52]) by mx.socionext.com with ESMTP; 24 Dec 2019 09:58:50 +0900 Received: from mail.mfilter.local (m-filter-2 [10.213.24.62]) by kinkan-ex.css.socionext.com (Postfix) with ESMTP id 78B7218008B; Tue, 24 Dec 2019 09:58:50 +0900 (JST) Received: from 172.31.9.51 (172.31.9.51) by m-FILTER with ESMTP; Tue, 24 Dec 2019 09:59:40 +0900 Received: from plum.e01.socionext.com (unknown [10.213.132.32]) by kinkan.css.socionext.com (Postfix) with ESMTP id EB3AA1A01CF; Tue, 24 Dec 2019 09:58:49 +0900 (JST) From: Kunihiko Hayashi To: Mark Brown , linux-spi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Masahiro Yamada , Keiji Hayashibara , Masami Hiramatsu , Jassi Brar , Kunihiko Hayashi Subject: [PATCH 5/5] spi: uniphier: Add DMA transfer mode support Date: Tue, 24 Dec 2019 09:58:27 +0900 Message-Id: <1577149107-30670-6-git-send-email-hayashi.kunihiko@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> References: <1577149107-30670-1-git-send-email-hayashi.kunihiko@socionext.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds DMA transfer mode support for UniPhier SPI controller. Since this controller requires simulteaneous transmission and reception, this indicates SPI_CONTROLLER_MUST_RX and SPI_CONTROLLER_MUST_TX. Because the supported dma controller has alignment restiction, there is also a restriction that 'maxburst' parameters in dma_slave_config corresponds to one word width. Signed-off-by: Kunihiko Hayashi --- drivers/spi/spi-uniphier.c | 200 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 2 deletions(-) -- 2.7.4 diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index caf0446..bf3af5b 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ struct uniphier_spi_priv { void __iomem *base; + dma_addr_t base_dma_addr; struct clk *clk; struct spi_master *master; struct completion xfer_done; @@ -32,6 +34,7 @@ struct uniphier_spi_priv { unsigned int rx_bytes; const u8 *tx_buf; u8 *rx_buf; + atomic_t dma_busy; bool is_save_param; u8 bits_per_word; @@ -61,11 +64,16 @@ struct uniphier_spi_priv { #define SSI_FPS_FSTRT BIT(14) #define SSI_SR 0x14 +#define SSI_SR_BUSY BIT(7) #define SSI_SR_RNE BIT(0) #define SSI_IE 0x18 +#define SSI_IE_TCIE BIT(4) #define SSI_IE_RCIE BIT(3) +#define SSI_IE_TXRE BIT(2) +#define SSI_IE_RXRE BIT(1) #define SSI_IE_RORIE BIT(0) +#define SSI_IE_ALL_MASK GENMASK(4, 0) #define SSI_IS 0x1c #define SSI_IS_RXRS BIT(9) @@ -87,6 +95,10 @@ struct uniphier_spi_priv { #define SSI_RXDR 0x24 #define SSI_FIFO_DEPTH 8U +#define SSI_FIFO_BURST_NUM 1 + +#define SSI_DMA_RX_BUSY BIT(1) +#define SSI_DMA_TX_BUSY BIT(0) static inline unsigned int bytes_per_word(unsigned int bits) { @@ -334,6 +346,128 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) writel(val, priv->base + SSI_FPS); } +static bool uniphier_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + unsigned int bpw = bytes_per_word(priv->bits_per_word); + + if ((!master->dma_tx && !master->dma_rx) + || (!master->dma_tx && t->tx_buf) + || (!master->dma_rx && t->rx_buf)) + return false; + + return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH; +} + +static void uniphier_spi_dma_rxcb(void *data) +{ + struct spi_master *master = data; + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_RXRE); + + if (!(state & SSI_DMA_TX_BUSY)) + spi_finalize_current_transfer(master); +} + +static void uniphier_spi_dma_txcb(void *data) +{ + struct spi_master *master = data; + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + + uniphier_spi_irq_disable(priv, SSI_IE_TXRE); + + if (!(state & SSI_DMA_RX_BUSY)) + spi_finalize_current_transfer(master); +} + +static int uniphier_spi_transfer_one_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL; + int buswidth; + + atomic_set(&priv->dma_busy, 0); + + uniphier_spi_set_fifo_threshold(priv, SSI_FIFO_BURST_NUM); + + if (priv->bits_per_word <= 8) + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + else if (priv->bits_per_word <= 16) + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + + if (priv->rx_buf) { + struct dma_slave_config rxconf = { + .direction = DMA_DEV_TO_MEM, + .src_addr = priv->base_dma_addr + SSI_RXDR, + .src_addr_width = buswidth, + .src_maxburst = SSI_FIFO_BURST_NUM, + }; + + dmaengine_slave_config(master->dma_rx, &rxconf); + + rxdesc = dmaengine_prep_slave_sg( + master->dma_rx, + t->rx_sg.sgl, t->rx_sg.nents, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rxdesc) + goto out_err_prep; + + rxdesc->callback = uniphier_spi_dma_rxcb; + rxdesc->callback_param = master; + + uniphier_spi_irq_enable(priv, SSI_IE_RXRE); + atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy); + + dmaengine_submit(rxdesc); + dma_async_issue_pending(master->dma_rx); + } + + if (priv->tx_buf) { + struct dma_slave_config txconf = { + .direction = DMA_MEM_TO_DEV, + .dst_addr = priv->base_dma_addr + SSI_TXDR, + .dst_addr_width = buswidth, + .dst_maxburst = SSI_FIFO_BURST_NUM, + }; + + dmaengine_slave_config(master->dma_tx, &txconf); + + txdesc = dmaengine_prep_slave_sg( + master->dma_tx, + t->tx_sg.sgl, t->tx_sg.nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!txdesc) + goto out_err_prep; + + txdesc->callback = uniphier_spi_dma_txcb; + txdesc->callback_param = master; + + uniphier_spi_irq_enable(priv, SSI_IE_TXRE); + atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy); + + dmaengine_submit(txdesc); + dma_async_issue_pending(master->dma_tx); + } + + /* signal that we need to wait for completion */ + return (priv->tx_buf || priv->rx_buf); + +out_err_prep: + if (rxdesc) + dmaengine_terminate_sync(master->dma_rx); + + return -EINVAL; +} + static int uniphier_spi_transfer_one_irq(struct spi_master *master, struct spi_device *spi, struct spi_transfer *t) @@ -395,6 +529,7 @@ static int uniphier_spi_transfer_one(struct spi_master *master, { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); unsigned long threshold; + bool use_dma; /* Terminate and return success for 0 byte length transfer */ if (!t->len) @@ -402,6 +537,10 @@ static int uniphier_spi_transfer_one(struct spi_master *master, uniphier_spi_setup_transfer(spi, t); + use_dma = master->can_dma ? master->can_dma(master, spi, t) : false; + if (use_dma) + return uniphier_spi_transfer_one_dma(master, spi, t); + /* * If the transfer operation will take longer than * SSI_POLL_TIMEOUT_US, it should use irq. @@ -445,7 +584,17 @@ static void uniphier_spi_handle_err(struct spi_master *master, val = SSI_FC_TXFFL | SSI_FC_RXFFL; writel(val, priv->base + SSI_FC); - uniphier_spi_irq_disable(priv, SSI_IE_RCIE | SSI_IE_RORIE); + uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK); + + if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) { + dmaengine_terminate_async(master->dma_tx); + atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy); + } + + if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) { + dmaengine_terminate_async(master->dma_rx); + atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy); + } } static irqreturn_t uniphier_spi_handler(int irq, void *dev_id) @@ -493,6 +642,9 @@ static int uniphier_spi_probe(struct platform_device *pdev) { struct uniphier_spi_priv *priv; struct spi_master *master; + struct resource *res; + struct dma_slave_caps caps; + u32 dma_tx_burst = 0, dma_rx_burst = 0; unsigned long clk_rate; int irq; int ret; @@ -507,11 +659,13 @@ static int uniphier_spi_probe(struct platform_device *pdev) priv->master = master; priv->is_save_param = false; - priv->base = devm_platform_ioremap_resource(pdev, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); goto out_master_put; } + priv->base_dma_addr = res->start; priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { @@ -556,7 +710,44 @@ static int uniphier_spi_probe(struct platform_device *pdev) master->unprepare_transfer_hardware = uniphier_spi_unprepare_transfer_hardware; master->handle_err = uniphier_spi_handle_err; + master->can_dma = uniphier_spi_can_dma; + master->num_chipselect = 1; + master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + + master->dma_tx = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR_OR_NULL(master->dma_tx)) { + if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) + goto out_disable_clk; + master->dma_tx = NULL; + dma_tx_burst = INT_MAX; + } else { + ret = dma_get_slave_caps(master->dma_tx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n", + ret); + goto out_disable_clk; + } + dma_tx_burst = caps.max_burst; + } + + master->dma_rx = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR_OR_NULL(master->dma_rx)) { + if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) + goto out_disable_clk; + master->dma_rx = NULL; + dma_rx_burst = INT_MAX; + } else { + ret = dma_get_slave_caps(master->dma_rx, &caps); + if (ret) { + dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n", + ret); + goto out_disable_clk; + } + dma_rx_burst = caps.max_burst; + } + + master->max_dma_len = min(dma_tx_burst, dma_rx_burst); ret = devm_spi_register_master(&pdev->dev, master); if (ret) @@ -576,6 +767,11 @@ static int uniphier_spi_remove(struct platform_device *pdev) { struct uniphier_spi_priv *priv = platform_get_drvdata(pdev); + if (priv->master->dma_tx) + dma_release_channel(priv->master->dma_tx); + if (priv->master->dma_rx) + dma_release_channel(priv->master->dma_rx); + clk_disable_unprepare(priv->clk); return 0;