From patchwork Wed Feb 13 07:36:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 158196 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp4752333jaa; Tue, 12 Feb 2019 23:37:32 -0800 (PST) X-Google-Smtp-Source: AHgI3IYPl+3xGsqKAz3Q5bT0ZoAeTqwpczBxY+RLH5GN2rgddlaE9tITDZ1rqblo2Zh/U+SH4ITA X-Received: by 2002:a17:902:8204:: with SMTP id x4mr8293078pln.59.1550043452306; Tue, 12 Feb 2019 23:37:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550043452; cv=none; d=google.com; s=arc-20160816; b=K1emeZOfQn3DAnsWPkQKpTN1YvyAoQMQrjM6cXSYtmIRt3eg38Ojoxg0kG2Ja7vtQT 9QqB9JbH4Q8OGUDYhWY4aPxbwSyt17JsIcNClHGwH5rlA+skjpVUSQPZtDJJ3Ooyy/dI BsxYEcvxFJ+7aVs7CY7zzQNfuBQZ1y1r1P1ROX3z+hKVWS/2yAGYo2aZtSox6PivRRpT ejTOKYgvFRFLgCUDZAj/pfcwhJj1Xr66n0xA30PkV8tkXxyHapn6Z1FNY5UJtMg+qDNx HimK45b6I9heiu81RC1xRI5uxgDZ2l3uF1k+fu5fFYZ8a9j7105oXiFjqR3KTXTJM605 Wqkg== 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:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=IuEgx9iAHvTk1jDMUjBUTSMxKsXFBOFl5qP8s21qcdQ=; b=snM3+9DZ+MOfrWppE8u7R2zu3Jqqe6whzSghFttkK5sPmkbjw6Ki+TjYehCy1DyCGB Vj/R/Q/py0SPWRniS2vWlAbILttkQR5bavPblCuZ4ElXb2fBwjBKilYQkTMHRXxBh4S7 Ah2LfQRP62c9qenoqsa2S1pO0FyJSsXO5v1AwgBFS0BPic6iPIIQA+8Dz5YrbMMYVonf Ljz2IGFhYo8rReYehUnAqXyDHLRYoo5hzxNtbi5m0TZglOSJk+qy9ajjQev314CDgBJg fdikrGHSmivLO4Qilyj02I+bU+WARUVqDLw2hFM+7oz6VQK/XrebdfLk9Zl2jEhTHje+ cYAg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=GibGtyYY; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e11si3229143pfn.124.2019.02.12.23.37.31; Tue, 12 Feb 2019 23:37:32 -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; dkim=pass header.i=@linaro.org header.s=google header.b=GibGtyYY; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389132AbfBMHhb (ORCPT + 31 others); Wed, 13 Feb 2019 02:37:31 -0500 Received: from mail-pg1-f193.google.com ([209.85.215.193]:41519 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732703AbfBMHh3 (ORCPT ); Wed, 13 Feb 2019 02:37:29 -0500 Received: by mail-pg1-f193.google.com with SMTP id m1so754562pgq.8 for ; Tue, 12 Feb 2019 23:37:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=IuEgx9iAHvTk1jDMUjBUTSMxKsXFBOFl5qP8s21qcdQ=; b=GibGtyYYnadfSrBALKN4QjZ4yKIUveoDbLl1BXiBMDObJ/35M4XJgslpfEPm+EPI/K wwcmpDOMoz7cc0AMDXRmhpJFpgU9EoHuKIKFRyep+6VTGkmlDO1XjyCEK+XQT3avcYrL jFrPUgx/GQb3XWrPrumSI+6/sWvyyQe31JrvLTLqNTjvjQ3IywJjE8LMpFvtOa+WGTd7 +tybEn6yQQfBZTz/T7dBZR97lAGAL2ovbBlYM4D6cV7oQvpO9r0hubv9GtltDsxiS0B2 ORfxjcxcDOZAFxqtsWRGSaWfQJe400tTo6SUWrGGLAuj3/GHvc6sJydJpevej7eVaWmS ZyNA== 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:in-reply-to:references; bh=IuEgx9iAHvTk1jDMUjBUTSMxKsXFBOFl5qP8s21qcdQ=; b=neCu90Wd+1SjnRMabZLCK9SfpwGDcSJHW8ZrojxH0SScuIWc2EzipASdecPSLoDNp6 SDAl+o0/vOQevH+j1lruUhqtpsQlJ8Yi/l0E31/Tt1R4qwtbtZWnYhpj0QS45l8YAqU0 ocrVOeLqm+I6ndQ8B1grlnmFOM+zpdHPtHhOiT88pJsX55tbOvtGjQWBKcbjSSm3yZ3B MsA1vR1g/HDDs+hv+HMUuK09G8wdcuUB9cwPPgo+aEZGAOk4HBM2SXSLPOwF9AOXax5C ObXuJbeDhAsNE4Gkg9OvjqU2y9fWeOFoEc5eMmjGJTyyPeE0FvIkbU3CVlQQIBJQC2vQ AX0A== X-Gm-Message-State: AHQUAuZR4sxFbNgWx3TW5zxG8rChRysr9Rjda5+2RESucdq1WCgPtCLZ MwRD/vTWKOhT73CL4UIt5JrVpQ== X-Received: by 2002:a63:da14:: with SMTP id c20mr7390174pgh.233.1550043448750; Tue, 12 Feb 2019 23:37:28 -0800 (PST) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.102]) by smtp.gmail.com with ESMTPSA id m67sm27060706pfm.73.2019.02.12.23.37.24 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 12 Feb 2019 23:37:28 -0800 (PST) From: Baolin Wang To: broonie@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com Cc: orsonzhai@gmail.com, zhang.lyra@gmail.com, lanqing.liu@unisoc.com, baolin.wang@linaro.org, linux-spi@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/3] dt-bindings: spi: Add the DMA properties for the SPI dma mode Date: Wed, 13 Feb 2019 15:36:10 +0800 Message-Id: <2be9d6de92507e5886433fb2cd55117c63b63d72.1550043082.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> References: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> In-Reply-To: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> References: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Lanqing Liu Add the DMA properties for the SPI dma mode. Signed-off-by: Lanqing Liu Signed-off-by: Baolin Wang --- Changes from v1: - Remove sprd,dma-slave-ids property. --- Documentation/devicetree/bindings/spi/spi-sprd.txt | 7 +++++++ 1 file changed, 7 insertions(+) -- 1.7.9.5 diff --git a/Documentation/devicetree/bindings/spi/spi-sprd.txt b/Documentation/devicetree/bindings/spi/spi-sprd.txt index bad211a..3c7eacc 100644 --- a/Documentation/devicetree/bindings/spi/spi-sprd.txt +++ b/Documentation/devicetree/bindings/spi/spi-sprd.txt @@ -14,6 +14,11 @@ Required properties: address on the SPI bus. Should be set to 1. - #size-cells: Should be set to 0. +Optional properties: +dma-names: Should contain names of the SPI used DMA channel. +dmas: Should contain DMA channels and DMA slave ids which the SPI used + sorted in the same order as the dma-names property. + Example: spi0: spi@70a00000{ compatible = "sprd,sc9860-spi"; @@ -21,6 +26,8 @@ spi0: spi@70a00000{ interrupts = ; clock-names = "spi", "source","enable"; clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>; + dma-names = "rx_chn", "tx_chn"; + dmas = <&apdma 11 11>, <&apdma 12 12>; #address-cells = <1>; #size-cells = <0>; }; From patchwork Wed Feb 13 07:36:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 158197 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp4752380jaa; Tue, 12 Feb 2019 23:37:36 -0800 (PST) X-Google-Smtp-Source: AHgI3IZw1mv9y/nF+TNutasTMk/BE1f+PhvJyPso2a1/KrPjOcm7iZ5EjNJeFxWsUO5dLlfK24M/ X-Received: by 2002:a63:574e:: with SMTP id h14mr7373965pgm.336.1550043456762; Tue, 12 Feb 2019 23:37:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550043456; cv=none; d=google.com; s=arc-20160816; b=uFkBbaPFDAlii6doqifqXcxpqT8YE7iRXOlN6M6pwHvkzs19qxVVaMgXdszoJ/ciPe 4toYX763gy82YUVyMwyAseBu/LDte6aBPvwOq4q1U3xQzJV23SXuAWSJ0oMvCcaWCFTA TpJDVTc2zPZdio9Rq4Sx8qJBhWwT60f243RURMsCBFl5AdkY7O1J8pQs3/3CelsowbFc v8gSOuQLJu/KYbGUI47sywhmzWhZl6DPQzJgKHl/tYgSnPZYqwje+ZM/Ay6BHitzlvE5 WDTz5AoKM6llNtw8mREfzwVvNMGAJDoMoSfwm/9RPz7bagjU6U26m1bxoA7zk78/GxIT ZjAw== 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:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature; bh=1SVsIQGCzKUloG3W1Q7JgONue0erTVU5jmvb7MTTzP0=; b=ugbMi6MATfzhzuqhkrtx7hHPe/lRRLK9faObcDhLoNKMsoDkv7TpfoX8G+GEYiZ54N tR/YAhvN8oKREndCySOoSjHjqS0bjXYTCdA9ok0nr6LkkMkI701CKwzq4hFM9qPw07DS DtnC/VIlBQc+89vJJaSdZSqwnxPxRslG15KC2xexlR4INZ15VNHn0AyzdinZpl7eJcS5 wyB8dh4NG7b/VF1VPTaLgWUh7yN6VlOYBbzO4m3LsS7Yk3xOtjPHJjMJpnI+G5preX4C kT8SYhXZRpKwqTMYCJJGCPX9funh4sUV17D2S5ISGVeq+7NlI2K0hknpWJ9HBV8pvjQv BEhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HdHNbWTi; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g28si4957548pgg.38.2019.02.12.23.37.36; Tue, 12 Feb 2019 23:37:36 -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; dkim=pass header.i=@linaro.org header.s=google header.b=HdHNbWTi; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388386AbfBMHhf (ORCPT + 31 others); Wed, 13 Feb 2019 02:37:35 -0500 Received: from mail-pf1-f194.google.com ([209.85.210.194]:43555 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732703AbfBMHhd (ORCPT ); Wed, 13 Feb 2019 02:37:33 -0500 Received: by mail-pf1-f194.google.com with SMTP id q17so756918pfh.10 for ; Tue, 12 Feb 2019 23:37:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=1SVsIQGCzKUloG3W1Q7JgONue0erTVU5jmvb7MTTzP0=; b=HdHNbWTiAKVaBz7zUB6LHoqBYW2s2AuGpn8ZCAZfTca/1ONruTUi+tHurhPQUFFu4f qOGFXRMYAaxFjCARRACDtXoU3Dv2tmc9L/nPmYpF1q2zBtjNZwlaO4g+ad7c90pPUhqP yneGbSVPkKo5upKCa89rLmH3ecqLNLstI+WJQgyZtlyIjg4sywd6A5C99BMXcFfjtCL1 6RlwsyBHbIb5Rqd7rR6f54j02HUz41foEsCzT9+S+gbNj4c7PAdtHMPzht3u9krzlAFg r2k8/oM1mqhwDYjRrM7BpwvvIX4TMQZwubLwLJBfaR/csYOcgZr092Ta3p8YnF51z2jt w7Cw== 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:in-reply-to:references; bh=1SVsIQGCzKUloG3W1Q7JgONue0erTVU5jmvb7MTTzP0=; b=D9yBBtf7w+ul3WD0p1Z+1EEcV7Q0IUbCjoz6J1ocMsjzgVOomRIskemcaNb8rN3Mc1 m9GH0JAUpW2v8s/ZKm9aqlsgpedBqcXw0szfh/rhmXhH5UkZ1Rc3Vuqvn/xbRGQMW5On YjtP1as2xhMbThsLf1pHhn/onAEOXFO4UnwdBGREsxqqhshIHAMK5+866rH2Z6rErpgK 49mOZDYDDiGAR6Ok2L0aF1LOFo/sjsS1s/NytWvCV9+H5BGJGiDk0TT7pU8/3B04Uytq xelwrg6xAQ+ztcEjxyiqG8cV89e0gGQR0JlfIngGAlYD6/AzpHk4AcbwN5YlOvLyJlBA NHqw== X-Gm-Message-State: AHQUAuYy5X8O6L0Hoj0OXp9a3awr+PpY/nJ9D0gppa4y0ivCEwI9Bdgx rp9LHFFGQfsh4okwJdy6WIUJjQ== X-Received: by 2002:a63:ea06:: with SMTP id c6mr7738024pgi.162.1550043452756; Tue, 12 Feb 2019 23:37:32 -0800 (PST) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.102]) by smtp.gmail.com with ESMTPSA id m67sm27060706pfm.73.2019.02.12.23.37.28 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 12 Feb 2019 23:37:32 -0800 (PST) From: Baolin Wang To: broonie@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com Cc: orsonzhai@gmail.com, zhang.lyra@gmail.com, lanqing.liu@unisoc.com, baolin.wang@linaro.org, linux-spi@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 3/3] spi: sprd: spi: sprd: Add DMA mode support Date: Wed, 13 Feb 2019 15:36:11 +0800 Message-Id: <3f9d23d4b250c5046f8c3411606aa9ffe807edd8.1550043082.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> References: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> In-Reply-To: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> References: <11e55b5f9b0d83649a5b81c7e3fdb667cd3ddc5b.1550043082.git.baolin.wang@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Lanqing Liu Add DMA mode support for the Spreadtrum SPI controller, and we will enable SPI interrupt to help to complete the SPI transfer work in DMA mode. Signed-off-by: Lanqing Liu Signed-off-by: Baolin Wang --- Changes from v1: - Implement the can_dma() ops. - Remove DMA slave id configuration. - Optimize the SPI irq enable/disable. --- drivers/spi/spi-sprd.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 3 deletions(-) -- 1.7.9.5 diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index d1ddeee..0c04a1d 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -2,6 +2,9 @@ // Copyright (C) 2018 Spreadtrum Communications Inc. #include +#include +#include +#include #include #include #include @@ -9,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -128,9 +132,25 @@ #define SPRD_SPI_DEFAULT_SOURCE 26000000 #define SPRD_SPI_MAX_SPEED_HZ 48000000 #define SPRD_SPI_AUTOSUSPEND_DELAY 100 +#define SPRD_SPI_DMA_STEP 8 + +enum sprd_spi_dma_channel { + SPI_RX, + SPI_TX, + SPI_MAX, +}; + +struct sprd_spi_dma { + bool enable; + struct dma_chan *dma_chan[SPI_MAX]; + enum dma_slave_buswidth width; + u32 fragmens_len; + u32 rx_len; +}; struct sprd_spi { void __iomem *base; + phys_addr_t phy_base; struct device *dev; struct clk *clk; int irq; @@ -142,6 +162,7 @@ struct sprd_spi { u32 hw_speed_hz; u32 len; int status; + struct sprd_spi_dma dma; struct completion xfer_completion; const void *tx_buf; void *rx_buf; @@ -433,6 +454,208 @@ static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) return ret; } +static void sprd_spi_irq_enable(struct sprd_spi *ss) +{ + u32 val; + + /* Clear interrupt status before enabling interrupt. */ + writel_relaxed(SPRD_SPI_TX_END_CLR | SPRD_SPI_RX_END_CLR, + ss->base + SPRD_SPI_INT_CLR); + /* Enable SPI interrupt only in DMA mode. */ + val = readl_relaxed(ss->base + SPRD_SPI_INT_EN); + writel_relaxed(val | SPRD_SPI_TX_END_INT_EN | + SPRD_SPI_RX_END_INT_EN, + ss->base + SPRD_SPI_INT_EN); +} + +static void sprd_spi_irq_disable(struct sprd_spi *ss) +{ + writel_relaxed(0, ss->base + SPRD_SPI_INT_EN); +} + +static void sprd_spi_dma_enable(struct sprd_spi *ss, bool enable) +{ + u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL2); + + if (enable) + val |= SPRD_SPI_DMA_EN; + else + val &= ~SPRD_SPI_DMA_EN; + + writel_relaxed(val, ss->base + SPRD_SPI_CTL2); +} + +static int sprd_spi_dma_submit(struct dma_chan *dma_chan, + struct dma_slave_config *c, + struct sg_table *sg, + enum dma_transfer_direction dir) +{ + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + unsigned long flags; + int ret; + + ret = dmaengine_slave_config(dma_chan, c); + if (ret < 0) + return ret; + + flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG, + SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT); + desc = dmaengine_prep_slave_sg(dma_chan, sg->sgl, sg->nents, dir, flags); + if (!desc) + return -ENODEV; + + cookie = dmaengine_submit(desc); + if (dma_submit_error(cookie)) + return dma_submit_error(cookie); + + dma_async_issue_pending(dma_chan); + + return 0; +} + +static int sprd_spi_dma_rx_config(struct sprd_spi *ss, struct spi_transfer *t) +{ + struct dma_chan *dma_chan = ss->dma.dma_chan[SPI_RX]; + struct dma_slave_config config = { + .src_addr = ss->phy_base, + .src_addr_width = ss->dma.width, + .dst_addr_width = ss->dma.width, + .dst_maxburst = ss->dma.fragmens_len, + }; + int ret; + + ret = sprd_spi_dma_submit(dma_chan, &config, &t->rx_sg, DMA_DEV_TO_MEM); + if (ret) + return ret; + + return ss->dma.rx_len; +} + +static int sprd_spi_dma_tx_config(struct sprd_spi *ss, struct spi_transfer *t) +{ + struct dma_chan *dma_chan = ss->dma.dma_chan[SPI_TX]; + struct dma_slave_config config = { + .dst_addr = ss->phy_base, + .src_addr_width = ss->dma.width, + .dst_addr_width = ss->dma.width, + .src_maxburst = ss->dma.fragmens_len, + }; + int ret; + + ret = sprd_spi_dma_submit(dma_chan, &config, &t->tx_sg, DMA_MEM_TO_DEV); + if (ret) + return ret; + + return t->len; +} + +static int sprd_spi_dma_request(struct sprd_spi *ss) +{ + ss->dma.dma_chan[SPI_RX] = dma_request_chan(ss->dev, "rx_chn"); + if (IS_ERR_OR_NULL(ss->dma.dma_chan[SPI_RX])) { + if (PTR_ERR(ss->dma.dma_chan[SPI_RX]) == -EPROBE_DEFER) + return PTR_ERR(ss->dma.dma_chan[SPI_RX]); + + dev_err(ss->dev, "request RX DMA channel failed!\n"); + return PTR_ERR(ss->dma.dma_chan[SPI_RX]); + } + + ss->dma.dma_chan[SPI_TX] = dma_request_chan(ss->dev, "tx_chn"); + if (IS_ERR_OR_NULL(ss->dma.dma_chan[SPI_TX])) { + if (PTR_ERR(ss->dma.dma_chan[SPI_TX]) == -EPROBE_DEFER) + return PTR_ERR(ss->dma.dma_chan[SPI_TX]); + + dev_err(ss->dev, "request TX DMA channel failed!\n"); + dma_release_channel(ss->dma.dma_chan[SPI_RX]); + return PTR_ERR(ss->dma.dma_chan[SPI_TX]); + } + + return 0; +} + +static void sprd_spi_dma_release(struct sprd_spi *ss) +{ + if (ss->dma.dma_chan[SPI_RX]) + dma_release_channel(ss->dma.dma_chan[SPI_RX]); + + if (ss->dma.dma_chan[SPI_TX]) + dma_release_channel(ss->dma.dma_chan[SPI_TX]); +} + +static int sprd_spi_dma_txrx_bufs(struct spi_device *sdev, + struct spi_transfer *t) +{ + struct sprd_spi *ss = spi_master_get_devdata(sdev->master); + u32 trans_len = ss->trans_len; + int ret, write_size = 0; + + reinit_completion(&ss->xfer_completion); + sprd_spi_irq_enable(ss); + if (ss->trans_mode & SPRD_SPI_TX_MODE) { + write_size = sprd_spi_dma_tx_config(ss, t); + sprd_spi_set_tx_length(ss, trans_len); + + /* + * For our 3 wires mode or dual TX line mode, we need + * to request the controller to transfer. + */ + if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) + sprd_spi_tx_req(ss); + } else { + sprd_spi_set_rx_length(ss, trans_len); + + /* + * For our 3 wires mode or dual TX line mode, we need + * to request the controller to read. + */ + if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) + sprd_spi_rx_req(ss); + else + write_size = ss->write_bufs(ss, trans_len); + } + + if (write_size < 0) { + ret = write_size; + dev_err(ss->dev, "failed to write, ret = %d\n", ret); + goto trans_complete; + } + + if (ss->trans_mode & SPRD_SPI_RX_MODE) { + /* + * Set up the DMA receive data length, which must be an + * integral multiple of fragment length. But when the length + * of received data is less than fragment length, DMA can be + * configured to receive data according to the actual length + * of received data. + */ + ss->dma.rx_len = t->len > ss->dma.fragmens_len ? + (t->len - t->len % ss->dma.fragmens_len) : + t->len; + ret = sprd_spi_dma_rx_config(ss, t); + if (ret < 0) { + dev_err(&sdev->dev, + "failed to configure rx DMA, ret = %d\n", ret); + goto trans_complete; + } + } + + sprd_spi_dma_enable(ss, true); + wait_for_completion(&(ss->xfer_completion)); + + if (ss->trans_mode & SPRD_SPI_TX_MODE) + ret = write_size; + else + ret = ss->dma.rx_len; + +trans_complete: + sprd_spi_dma_enable(ss, false); + sprd_spi_enter_idle(ss); + sprd_spi_irq_disable(ss); + + return ret; +} + static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz) { /* @@ -518,16 +741,22 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev, ss->trans_len = t->len; ss->read_bufs = sprd_spi_read_bufs_u8; ss->write_bufs = sprd_spi_write_bufs_u8; + ss->dma.width = DMA_SLAVE_BUSWIDTH_1_BYTE; + ss->dma.fragmens_len = SPRD_SPI_DMA_STEP; break; case 16: ss->trans_len = t->len >> 1; ss->read_bufs = sprd_spi_read_bufs_u16; ss->write_bufs = sprd_spi_write_bufs_u16; + ss->dma.width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ss->dma.fragmens_len = SPRD_SPI_DMA_STEP << 1; break; case 32: ss->trans_len = t->len >> 2; ss->read_bufs = sprd_spi_read_bufs_u32; ss->write_bufs = sprd_spi_write_bufs_u32; + ss->dma.width = DMA_SLAVE_BUSWIDTH_4_BYTES; + ss->dma.fragmens_len = SPRD_SPI_DMA_STEP << 2; break; default: return -EINVAL; @@ -565,7 +794,11 @@ static int sprd_spi_transfer_one(struct spi_controller *sctlr, if (ret) goto setup_err; - ret = sprd_spi_txrx_bufs(sdev, t); + if (sctlr->can_dma(sctlr, sdev, t)) + ret = sprd_spi_dma_txrx_bufs(sdev, t); + else + ret = sprd_spi_txrx_bufs(sdev, t); + if (ret == t->len) ret = 0; else if (ret >= 0) @@ -592,6 +825,11 @@ static irqreturn_t sprd_spi_handle_irq(int irq, void *data) if (val & SPRD_SPI_MASK_RX_END) { writel_relaxed(SPRD_SPI_RX_END_CLR, ss->base + SPRD_SPI_INT_CLR); + if (ss->dma.rx_len < ss->len) { + ss->rx_buf += ss->dma.rx_len; + ss->dma.rx_len += + ss->read_bufs(ss, ss->len - ss->dma.rx_len); + } complete(&ss->xfer_completion); return IRQ_HANDLED; @@ -649,6 +887,35 @@ static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss) return 0; } +static bool sprd_spi_can_dma(struct spi_controller *sctlr, + struct spi_device *spi, struct spi_transfer *t) +{ + struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + + return ss->dma.enable && (t->len > SPRD_SPI_FIFO_SIZE); +} + +static int sprd_spi_dma_init(struct platform_device *pdev, struct sprd_spi *ss) +{ + int ret; + + ret = sprd_spi_dma_request(ss); + if (ret) { + if (ret == -EPROBE_DEFER) + return ret; + + dev_warn(&pdev->dev, + "failed to request dma, enter no dma mode, ret = %d\n", + ret); + + return 0; + } + + ss->dma.enable = true; + + return 0; +} + static int sprd_spi_probe(struct platform_device *pdev) { struct spi_controller *sctlr; @@ -669,12 +936,14 @@ static int sprd_spi_probe(struct platform_device *pdev) goto free_controller; } + ss->phy_base = res->start; ss->dev = &pdev->dev; sctlr->dev.of_node = pdev->dev.of_node; sctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE | SPI_TX_DUAL; sctlr->bus_num = pdev->id; sctlr->set_cs = sprd_spi_chipselect; sctlr->transfer_one = sprd_spi_transfer_one; + sctlr->can_dma = sprd_spi_can_dma; sctlr->auto_runtime_pm = true; sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1, SPRD_SPI_MAX_SPEED_HZ); @@ -689,10 +958,14 @@ static int sprd_spi_probe(struct platform_device *pdev) if (ret) goto free_controller; - ret = clk_prepare_enable(ss->clk); + ret = sprd_spi_dma_init(pdev, ss); if (ret) goto free_controller; + ret = clk_prepare_enable(ss->clk); + if (ret) + goto release_dma; + ret = pm_runtime_set_active(&pdev->dev); if (ret < 0) goto disable_clk; @@ -721,6 +994,8 @@ static int sprd_spi_probe(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); disable_clk: clk_disable_unprepare(ss->clk); +release_dma: + sprd_spi_dma_release(ss); free_controller: spi_controller_put(sctlr); @@ -741,6 +1016,8 @@ static int sprd_spi_remove(struct platform_device *pdev) spi_controller_suspend(sctlr); + if (ss->dma.enable) + sprd_spi_dma_release(ss); clk_disable_unprepare(ss->clk); pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -753,6 +1030,9 @@ static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev) struct spi_controller *sctlr = dev_get_drvdata(dev); struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + if (ss->dma.enable) + sprd_spi_dma_release(ss); + clk_disable_unprepare(ss->clk); return 0; @@ -768,7 +1048,14 @@ static int __maybe_unused sprd_spi_runtime_resume(struct device *dev) if (ret) return ret; - return 0; + if (!ss->dma.enable) + return 0; + + ret = sprd_spi_dma_request(ss); + if (ret) + clk_disable_unprepare(ss->clk); + + return ret; } static const struct dev_pm_ops sprd_spi_pm_ops = {