From patchwork Tue Oct 3 23:58:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 821077 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; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="pesFtj0c"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3y6GFl6fhmz9sPs for ; Wed, 4 Oct 2017 10:58:35 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751430AbdJCX6f (ORCPT ); Tue, 3 Oct 2017 19:58:35 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:43056 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750865AbdJCX6e (ORCPT ); Tue, 3 Oct 2017 19:58:34 -0400 Received: by mail-wm0-f68.google.com with SMTP id m72so12586489wmc.0; Tue, 03 Oct 2017 16:58:33 -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:in-reply-to:references :in-reply-to:references; bh=qWcDPEYyuW0r4EleaRhSgkudR7pPOocxlAe5x5zv3Eo=; b=pesFtj0cw1UkUl/xs8m+azoVlEjd4okKG6maI+bAMPtvDrK5b7uSSYuMAC/3jeysry GCAZu5oSmeCzxHSoKeQtIWIQx5NWkeAaYWHlXKI1oViUlHpBf9qNF3FH6FI3g4DYlDPE TrTY6EcQuMXxzZmgocZjwrCOIhkZIj+csVJ/MDDlqqSGH8X7aRZYspkgDt6OvylD5jO8 CjYfv1utqgV+fTp049TZiRhU+NYlBM7dJaUnE81jzstxuM560eFL0AVT8rz2uhxjICRZ I7k1AQT3xipOKZSDP+F03aG/hmMfIPn+flehHHAPeMGyRRyQyDFPLWbpHwuRUzk3yTYk GKug== 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=qWcDPEYyuW0r4EleaRhSgkudR7pPOocxlAe5x5zv3Eo=; b=jPHd4V8m3HUzGbeh0DlBwPduSBjUHVfk7pUvYCcFGGvIkRbYpQpcYWX050IVGeFLym aQ2s6OaAe7Igy7ESUP99Ehur8Anv3dNZwUQBmOpQ/pD13e9ipYahb5zT3Mo55jL8XkS6 HJpa5y1iS1S2j5sp4RhHokDqyNI/H9Mso8N7eqXd7UyAijat6ZqEcTsUf2wOXcvNSYJr YsarKT6lygs4yEDTEEv7Y0wS/LTuyONoWkFkYyqBbPs6WfsjtwOE0MPQuFjHl6TZ0y3A VLDXQ4dlDC9kVmIa5Zf7x05QBtGYY6J+8x4EzuqgGRStT92bJe9psc4K4dbgyuNUpa8f 8UmA== X-Gm-Message-State: AMCzsaW4GxYT/ZzNpLiGyBeQZHZOjNlfAzzuPvfcQq1voxiJxQc1TLjF z8KpQwiEsZH3XvfZA48IwLw= X-Google-Smtp-Source: AOwi7QA9i1/iNIDJuODCmLG5ninS6V8r2Y1D+OHwYbL7zjRTKg2OX8zfutrKsFsH1O11CRF3SmJ4dw== X-Received: by 10.28.227.68 with SMTP id a65mr16215548wmh.88.1507075113049; Tue, 03 Oct 2017 16:58:33 -0700 (PDT) Received: from localhost.localdomain (ppp109-252-55-163.pppoe.spdop.ru. [109.252.55.163]) by smtp.gmail.com with ESMTPSA id r21sm8702808wmd.26.2017.10.03.16.58.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Oct 2017 16:58:32 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Vinod Koul , Laxman Dewangan , Stephen Warren Cc: dmaengine@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH v2 1/3] dt-bindings: Add DT binding for NVIDIA Tegra AHB DMA controller Date: Wed, 4 Oct 2017 02:58:01 +0300 Message-Id: X-Mailer: git-send-email 2.14.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Document DT binding for the NVIDIA Tegra AHB DMA controller that presents on Tegra20/30 SoC's. Signed-off-by: Dmitry Osipenko --- .../bindings/dma/nvidia,tegra20-ahbdma.txt | 23 +++++++++ include/dt-bindings/dma/tegra-ahb-dma.h | 56 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/nvidia,tegra20-ahbdma.txt create mode 100644 include/dt-bindings/dma/tegra-ahb-dma.h diff --git a/Documentation/devicetree/bindings/dma/nvidia,tegra20-ahbdma.txt b/Documentation/devicetree/bindings/dma/nvidia,tegra20-ahbdma.txt new file mode 100644 index 000000000000..9fa393766930 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/nvidia,tegra20-ahbdma.txt @@ -0,0 +1,23 @@ +* NVIDIA Tegra AHB DMA controller + +Required properties: +- compatible: Must be "nvidia,tegra20-ahbdma" +- reg: Must contain registers base address and length. +- interrupts: Must contain one entry, DMA controller interrupt. +- clocks: Must contain one entry, DMA controller clock. +- resets : Must contain one entry, DMA controller reset. +- #dma-cells: Must be <1>. The cell represents DMA request select value + for the peripheral. For more details consult the Tegra TRM + documentation, in particular REQ_SEL field of the AHB DMA + channel control register. + +Example: + +ahbdma: ahbdma@60008000 { + compatible = "nvidia,tegra20-ahbdma"; + reg = <0x60008000 0x2000>; + interrupts = ; + clocks = <&tegra_car TEGRA20_CLK_AHBDMA>; + resets = <&tegra_car 33>; + #dma-cells = <1>; +}; diff --git a/include/dt-bindings/dma/tegra-ahb-dma.h b/include/dt-bindings/dma/tegra-ahb-dma.h new file mode 100644 index 000000000000..7eb4fb86e0d2 --- /dev/null +++ b/include/dt-bindings/dma/tegra-ahb-dma.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Dmitry Osipenko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __DT_BINDINGS_TEGRA_AHBDMA_H +#define __DT_BINDINGS_TEGRA_AHBDMA_H + +#define TEGRA_AHBDMA_TRIG_HRQ2_XRQ_C 2 +#define TEGRA_AHBDMA_TRIG_HRQ2_XRQ_D 3 +#define TEGRA_AHBDMA_TRIG_HRQ4_N_A 4 +#define TEGRA_AHBDMA_TRIG_HRQ5_N_A 5 +#define TEGRA_AHBDMA_TRIG_HRQ6_TMR1 6 +#define TEGRA_AHBDMA_TRIG_HRQ7_TMR2 7 +#define TEGRA_AHBDMA_TRIG_AHB_DMA_0 8 +#define TEGRA_AHBDMA_TRIG_AHB_DMA_1 9 +#define TEGRA_AHBDMA_TRIG_AHB_DMA_2 10 +#define TEGRA_AHBDMA_TRIG_AHB_DMA_3 11 +#define TEGRA_AHBDMA_TRIG_SMP_28 12 +#define TEGRA_AHBDMA_TRIG_SMP_29 13 +#define TEGRA_AHBDMA_TRIG_SMP_30 14 +#define TEGRA_AHBDMA_TRIG_SMP_31 15 + +#define TEGRA_AHBDMA_TRIG_N_A 16 + +#define TEGRA_AHBDMA_REQ_CNTR_REQ 0 +#define TEGRA_AHBDMA_REQ_SMP_17 1 +#define TEGRA_AHBDMA_REQ_SMP_18 2 +#define TEGRA_AHBDMA_REQ_SMP_19 3 +#define TEGRA_AHBDMA_REQ_SMP_20 4 +#define TEGRA_AHBDMA_REQ_SMP_21 5 +#define TEGRA_AHBDMA_REQ_SMP_22 6 +#define TEGRA_AHBDMA_REQ_SMP_23 7 +#define TEGRA_AHBDMA_REQ_SMP_24 8 +#define TEGRA_AHBDMA_REQ_SMP_25 9 +#define TEGRA_AHBDMA_REQ_SMP_26 10 +#define TEGRA_AHBDMA_REQ_HOST1X 11 +#define TEGRA_AHBDMA_REQ_SRQ0_N_A 12 +#define TEGRA_AHBDMA_REQ_SRQ1_N_A 13 +#define TEGRA_AHBDMA_REQ_SRQ0_XRQ_A 14 +#define TEGRA_AHBDMA_REQ_SRQ1_XRQ_B 15 + +#define TEGRA_AHBDMA_REQ_N_A 16 + +#endif /* __DT_BINDINGS_TEGRA_AHBDMA_H */ From patchwork Tue Oct 3 23:58:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 821078 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; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="N/+WLCRT"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3y6GFp67WQz9rxj for ; Wed, 4 Oct 2017 10:58:38 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751384AbdJCX6h (ORCPT ); Tue, 3 Oct 2017 19:58:37 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:33831 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750865AbdJCX6g (ORCPT ); Tue, 3 Oct 2017 19:58:36 -0400 Received: by mail-wr0-f194.google.com with SMTP id z1so6967439wre.1; Tue, 03 Oct 2017 16:58:35 -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:in-reply-to:references :in-reply-to:references; bh=/dvSfJw/XWQBWuz8UtsP7YCPxzs2NVUCIRODS8hoVSU=; b=N/+WLCRTfBfH/wwTwM4BEb8kXKbZ+hmYSpziwmC+j0RZiL/vVVc44xho4BHuAYXx0E GyGJupmLxTgsehsbGgQz6OIhg0cxYrwsOy2BsT7590lTtH6Hc+xND6fjHKNWLDEdcjQ8 UA/7QD06t867s0rJxfTCqxcXirPFxjyw092AK6ldhdddru3y9OgVzh8zPyZce5w/UYgD yj87oXb28EOFGI3HAZrVgxCeBvLb+jvJ0cHC0+yRYDkv3M4RZqJOZ43paQLrsvL7wRwp Hp5zVQHJ2NN926MM9EC4CfaiZ0x10BYl6kBdizWN3IkEExnofdzVQZwEKtq1shQZ/YF+ Nn9g== 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=/dvSfJw/XWQBWuz8UtsP7YCPxzs2NVUCIRODS8hoVSU=; b=Kzjss7m5wwnq75jUwLVfG3GpkXQuvVRP2ocBTlLxl82nLF5HNj4LT8cscOH0o3xIaX OCQyQE+muKYiu7Iv2RDNPElCeoJLUhLPgn+6xo2acK52cP1739M/esiQZa2HL6oth5PF THDlN54JUDH8GVOQmsEaK59QrnXDOTex8Bm5RaD45+TnF/Jo9RyW5ON/2X3rzpZnOtHh bdDJWc9Vewn+FOOhnWCNw79kswCTE+tHk0yq6ZyQHoKNqvQfQICY/xfURmoOhxWVLLt3 f23g1tL/VBVkM6MC+5euKPVyorgSSLqV2CT7cEzVyKbPZ854fyhjfjeViTBMIp3nd6Pi kxYA== X-Gm-Message-State: AHPjjUielzMmu8YO6R4P6D3znSBYoU5pAwv3jh3Kau3d3M9hph3VujGj vgXxpTra5rv8zKpf+8tz7Ss= X-Google-Smtp-Source: AOwi7QAfoA/w6/fZPM0aBoHNnvobblGyCJ/gW1dZgo1+j971IDAz31BsnuOIEbj0sefr72PwSAm8IA== X-Received: by 10.223.171.206 with SMTP id s72mr18476782wrc.27.1507075114951; Tue, 03 Oct 2017 16:58:34 -0700 (PDT) Received: from localhost.localdomain (ppp109-252-55-163.pppoe.spdop.ru. [109.252.55.163]) by smtp.gmail.com with ESMTPSA id r21sm8702808wmd.26.2017.10.03.16.58.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Oct 2017 16:58:34 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Vinod Koul , Laxman Dewangan , Stephen Warren Cc: dmaengine@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH v2 2/3] dmaengine: Add driver for NVIDIA Tegra AHB DMA controller Date: Wed, 4 Oct 2017 02:58:02 +0300 Message-Id: <9ef93a0054a6a2e27b72e5bfeebe81e5ab11a224.1507073384.git.digetx@gmail.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org AHB DMA controller presents on Tegra20/30 SoC's, it supports transfers memory <-> AHB bus peripherals as well as mem-to-mem transfers. Driver doesn't yet implement transfers larger than 64K and scatter-gather transfers that have NENT > 1, HW doesn't have native support for these cases, mem-to-mem isn't implemented as well. Signed-off-by: Dmitry Osipenko --- drivers/dma/Kconfig | 10 + drivers/dma/Makefile | 1 + drivers/dma/tegra20-ahb-dma.c | 630 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 641 insertions(+) create mode 100644 drivers/dma/tegra20-ahb-dma.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 04e381b522b4..7d132aa85174 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -512,6 +512,16 @@ config TXX9_DMAC Support the TXx9 SoC internal DMA controller. This can be integrated in chips such as the Toshiba TX4927/38/39. +config TEGRA20_AHB_DMA + tristate "NVIDIA Tegra20 AHB DMA support" + depends on ARCH_TEGRA || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the NVIDIA Tegra20 AHB DMA controller driver. + This DMA controller transfers data from memory to AHB peripherals + or vice versa, it supports memory to memory data transfer as well. + config TEGRA20_APB_DMA bool "NVIDIA Tegra20 APB DMA support" depends on ARCH_TEGRA diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a145ad1426bc..f3d284bf6d65 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_STM32_DMA) += stm32-dma.o obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o +obj-$(CONFIG_TEGRA20_AHB_DMA) += tegra20-ahb-dma.o obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o obj-$(CONFIG_TIMB_DMA) += timb_dma.o diff --git a/drivers/dma/tegra20-ahb-dma.c b/drivers/dma/tegra20-ahb-dma.c new file mode 100644 index 000000000000..2d176a5536aa --- /dev/null +++ b/drivers/dma/tegra20-ahb-dma.c @@ -0,0 +1,630 @@ +/* + * Copyright 2017 Dmitry Osipenko + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "virt-dma.h" + +#define AHBDMA_CMD 0x0 +#define AHBDMA_CMD_ENABLE BIT(31) + +#define AHBDMA_IRQ_ENB_MASK 0x20 +#define AHBDMA_IRQ_ENB_CH(ch) BIT(ch) + +#define AHBDMA_CH_BASE(ch) (0x1000 + (ch) * 0x20) + +#define AHBDMA_CH_CSR 0x0 +#define AHBDMA_CH_ADDR_WRAP BIT(18) +#define AHBDMA_CH_FLOW BIT(24) +#define AHBDMA_CH_ONCE BIT(26) +#define AHBDMA_CH_DIR_TO_XMB BIT(27) +#define AHBDMA_CH_IE_EOC BIT(30) +#define AHBDMA_CH_ENABLE BIT(31) +#define AHBDMA_CH_REQ_SEL_SHIFT 16 +#define AHBDMA_CH_WCOUNT_MASK GENMASK(15, 2) + +#define AHBDMA_CH_STA 0x4 +#define AHBDMA_CH_IS_EOC BIT(30) + +#define AHBDMA_CH_AHB_PTR 0x10 + +#define AHBDMA_CH_AHB_SEQ 0x14 +#define AHBDMA_CH_INTR_ENB BIT(31) +#define AHBDMA_CH_AHB_BURST_SHIFT 24 +#define AHBDMA_CH_AHB_BURST_1 2 +#define AHBDMA_CH_AHB_BURST_4 3 +#define AHBDMA_CH_AHB_BURST_8 4 + +#define AHBDMA_CH_XMB_PTR 0x18 + +#define AHBDMA_BUS_WIDTH BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) + +#define AHBDMA_DIRECTIONS BIT(DMA_DEV_TO_MEM) | \ + BIT(DMA_MEM_TO_DEV) + +#define AHBDMA_BURST_COMPLETE_TIME 20 + +struct tegra_ahbdma_tx_desc { + struct virt_dma_desc vdesc; + dma_addr_t mem_addr; + phys_addr_t ahb_addr; + u32 ahb_seq; + u32 csr; +}; + +struct tegra_ahbdma_chan { + struct tegra_ahbdma_tx_desc *active_tx; + struct virt_dma_chan vchan; + struct completion idling; + void __iomem *regs; + phys_addr_t ahb_addr; + u32 ahb_seq; + u32 csr; + unsigned int of_req_sel; + bool of_slave; +}; + +struct tegra_ahbdma { + struct tegra_ahbdma_chan channels[4]; + struct dma_device dma_dev; + struct reset_control *rst; + struct clk *clk; + void __iomem *regs; +}; + +static inline struct tegra_ahbdma_chan *to_ahbdma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct tegra_ahbdma_chan, vchan.chan); +} + +static inline struct tegra_ahbdma_tx_desc *to_ahbdma_tx_desc( + struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct tegra_ahbdma_tx_desc, vdesc); +} + +static struct tegra_ahbdma_tx_desc *tegra_ahbdma_get_next_tx( + struct tegra_ahbdma_chan *chan) +{ + struct virt_dma_desc *vdesc = vchan_next_desc(&chan->vchan); + + if (vdesc) + list_del(&vdesc->node); + + return vdesc ? to_ahbdma_tx_desc(vdesc) : NULL; +} + +static void tegra_ahbdma_issue_next_tx(struct tegra_ahbdma_chan *chan) +{ + struct tegra_ahbdma_tx_desc *tx = tegra_ahbdma_get_next_tx(chan); + + if (tx) { + writel_relaxed(tx->ahb_seq, chan->regs + AHBDMA_CH_AHB_SEQ); + writel_relaxed(tx->ahb_addr, chan->regs + AHBDMA_CH_AHB_PTR); + writel_relaxed(tx->mem_addr, chan->regs + AHBDMA_CH_XMB_PTR); + writel_relaxed(tx->csr, chan->regs + AHBDMA_CH_CSR); + + reinit_completion(&chan->idling); + } else + complete_all(&chan->idling); + + chan->active_tx = tx; +} + +static bool tegra_ahbdma_clear_interrupt(struct tegra_ahbdma_chan *chan) +{ + u32 status = readl_relaxed(chan->regs + AHBDMA_CH_STA); + + if (status & AHBDMA_CH_IS_EOC) { + writel_relaxed(AHBDMA_CH_IS_EOC, chan->regs + AHBDMA_CH_STA); + + return true; + } + + return false; +} + +static bool tegra_ahbdma_handle_channel(struct tegra_ahbdma_chan *chan) +{ + struct tegra_ahbdma_tx_desc *tx; + unsigned long flags; + bool intr = false; + bool cyclic; + + spin_lock_irqsave(&chan->vchan.lock, flags); + + tx = chan->active_tx; + if (tx) + intr = tegra_ahbdma_clear_interrupt(chan); + + if (intr) { + cyclic = !(tx->csr & AHBDMA_CH_ONCE); + + if (!cyclic) + tegra_ahbdma_issue_next_tx(chan); + + if (cyclic) + vchan_cyclic_callback(&tx->vdesc); + else + vchan_cookie_complete(&tx->vdesc); + } + + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + return intr; +} + +static irqreturn_t tegra_ahbdma_isr(int irq, void *dev_id) +{ + struct tegra_ahbdma *tdma = dev_id; + bool handled; + + handled = tegra_ahbdma_handle_channel(&tdma->channels[0]); + handled |= tegra_ahbdma_handle_channel(&tdma->channels[1]); + handled |= tegra_ahbdma_handle_channel(&tdma->channels[2]); + handled |= tegra_ahbdma_handle_channel(&tdma->channels[3]); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void tegra_ahbdma_tx_desc_free(struct virt_dma_desc *vdesc) +{ + kfree(to_ahbdma_tx_desc(vdesc)); +} + +static struct dma_async_tx_descriptor *tegra_ahbdma_prep( + struct dma_chan *chan, + enum dma_transfer_direction dir, + unsigned long flags, + dma_addr_t paddr, + size_t size, + bool cyclic) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + struct tegra_ahbdma_tx_desc *tx; + u32 csr = ahbdma_chan->csr; + + /* size and alignments should fulfill HW requirements */ + if (size < 4 || size & 3 || paddr & 3) + return NULL; + + tx = kzalloc(sizeof(*tx), GFP_NOWAIT); + if (!tx) + return NULL; + + if (dir == DMA_DEV_TO_MEM) + csr |= AHBDMA_CH_DIR_TO_XMB; + + if (!cyclic) + csr |= AHBDMA_CH_ONCE; + + tx->csr = csr | (size - sizeof(u32)); + tx->ahb_seq = ahbdma_chan->ahb_seq; + tx->ahb_addr = ahbdma_chan->ahb_addr; + tx->mem_addr = paddr; + + return vchan_tx_prep(&ahbdma_chan->vchan, &tx->vdesc, flags); +} + +static struct dma_async_tx_descriptor *tegra_ahbdma_prep_slave_sg( + struct dma_chan *chan, + struct scatterlist *sgl, + unsigned int sg_len, + enum dma_transfer_direction dir, + unsigned long flags, + void *context) +{ + /* unimplemented */ + if (sg_len != 1 || sg_dma_len(sgl) > SZ_64K) + return NULL; + + return tegra_ahbdma_prep(chan, dir, flags, sg_dma_address(sgl), + sg_dma_len(sgl), false); +} + +static struct dma_async_tx_descriptor *tegra_ahbdma_prep_dma_cyclic( + struct dma_chan *chan, + dma_addr_t buf_addr, + size_t buf_len, + size_t period_len, + enum dma_transfer_direction dir, + unsigned long flags) +{ + /* unimplemented */ + if (buf_len != period_len || buf_len > SZ_64K) + return NULL; + + return tegra_ahbdma_prep(chan, dir, flags, buf_addr, buf_len, true); +} + +static void tegra_ahbdma_issue_pending(struct dma_chan *chan) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + struct virt_dma_chan *vchan = &ahbdma_chan->vchan; + unsigned long flags; + + spin_lock_irqsave(&vchan->lock, flags); + + if (vchan_issue_pending(vchan) && !ahbdma_chan->active_tx) + tegra_ahbdma_issue_next_tx(ahbdma_chan); + + spin_unlock_irqrestore(&vchan->lock, flags); +} + +static size_t tegra_ahbdma_residual(struct tegra_ahbdma_chan *chan) +{ + u32 status = readl_relaxed(chan->regs + AHBDMA_CH_STA); + + return (status & AHBDMA_CH_WCOUNT_MASK); +} + +static enum dma_status tegra_ahbdma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + struct tegra_ahbdma_tx_desc *tx; + struct virt_dma_desc *vdesc; + enum dma_status cookie_status; + unsigned long flags; + size_t residual; + + spin_lock_irqsave(&ahbdma_chan->vchan.lock, flags); + + cookie_status = dma_cookie_status(chan, cookie, state); + if (cookie_status == DMA_COMPLETE) + goto unlock; + + vdesc = vchan_find_desc(&ahbdma_chan->vchan, cookie); + if (!vdesc) + residual = 0; + else { + tx = to_ahbdma_tx_desc(vdesc); + + if (tx == ahbdma_chan->active_tx) + residual = tegra_ahbdma_residual(ahbdma_chan); + else + residual = tx->csr & AHBDMA_CH_WCOUNT_MASK; + + residual += sizeof(u32); + } + + dma_set_residue(state, residual); + +unlock: + spin_unlock_irqrestore(&ahbdma_chan->vchan.lock, flags); + + return cookie_status; +} + +static int tegra_ahbdma_terminate_all(struct dma_chan *chan) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + u32 csr; + + spin_lock_irqsave(&ahbdma_chan->vchan.lock, flags); + + csr = readl_relaxed(ahbdma_chan->regs + AHBDMA_CH_CSR); + writel_relaxed(csr & ~AHBDMA_CH_ENABLE, + ahbdma_chan->regs + AHBDMA_CH_CSR); + + if (ahbdma_chan->active_tx) { + udelay(AHBDMA_BURST_COMPLETE_TIME); + + writel_relaxed(AHBDMA_CH_IS_EOC, + ahbdma_chan->regs + AHBDMA_CH_STA); + + ahbdma_chan->active_tx = NULL; + } + + vchan_get_all_descriptors(&ahbdma_chan->vchan, &head); + complete_all(&ahbdma_chan->idling); + + spin_unlock_irqrestore(&ahbdma_chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&ahbdma_chan->vchan, &head); + + return 0; +} + +static int tegra_ahbdma_config(struct dma_chan *chan, + struct dma_slave_config *sconfig) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + enum dma_transfer_direction dir = sconfig->direction; + u32 burst, ahb_seq, csr; + unsigned int slave_id; + phys_addr_t ahb_addr; + + if (sconfig->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES || + sconfig->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) + return -EINVAL; + + switch (dir) { + case DMA_DEV_TO_MEM: + burst = sconfig->src_maxburst; + ahb_addr = sconfig->src_addr; + break; + case DMA_MEM_TO_DEV: + burst = sconfig->dst_maxburst; + ahb_addr = sconfig->dst_addr; + break; + default: + return -EINVAL; + } + + switch (burst) { + case 1: + burst = AHBDMA_CH_AHB_BURST_1; + break; + case 4: + burst = AHBDMA_CH_AHB_BURST_4; + break; + case 8: + burst = AHBDMA_CH_AHB_BURST_8; + break; + default: + return -EINVAL; + } + + if (ahb_addr & 3) + return -EINVAL; + + ahb_seq = burst << AHBDMA_CH_AHB_BURST_SHIFT; + ahb_seq |= AHBDMA_CH_INTR_ENB; + + csr = AHBDMA_CH_ENABLE; + csr |= AHBDMA_CH_IE_EOC; + + if (ahbdma_chan->of_slave || sconfig->device_fc) { + if (ahbdma_chan->of_req_sel < TEGRA_AHBDMA_REQ_N_A) + slave_id = ahbdma_chan->of_req_sel; + else + slave_id = sconfig->slave_id; + + if (slave_id > 15) + return -EINVAL; + + ahb_seq |= AHBDMA_CH_ADDR_WRAP; + + csr |= slave_id << AHBDMA_CH_REQ_SEL_SHIFT; + csr |= AHBDMA_CH_FLOW; + } + + ahbdma_chan->csr = csr; + ahbdma_chan->ahb_seq = ahb_seq; + ahbdma_chan->ahb_addr = ahb_addr; + + return 0; +} + +static void tegra_ahbdma_synchronize(struct dma_chan *chan) +{ + struct tegra_ahbdma_chan *ahbdma_chan = to_ahbdma_chan(chan); + + wait_for_completion(&ahbdma_chan->idling); + vchan_synchronize(&ahbdma_chan->vchan); +} + +static void tegra_ahbdma_free_chan_resources(struct dma_chan *chan) +{ + vchan_free_chan_resources(to_virt_chan(chan)); +} + +static void tegra_ahbdma_init_channel(struct tegra_ahbdma *tdma, + unsigned int chan_id) +{ + struct tegra_ahbdma_chan *ahbdma_chan = &tdma->channels[chan_id]; + struct dma_device *dma_dev = &tdma->dma_dev; + + vchan_init(&ahbdma_chan->vchan, dma_dev); + init_completion(&ahbdma_chan->idling); + complete(&ahbdma_chan->idling); + + ahbdma_chan->regs = tdma->regs + AHBDMA_CH_BASE(chan_id); + ahbdma_chan->vchan.desc_free = tegra_ahbdma_tx_desc_free; + ahbdma_chan->of_req_sel = TEGRA_AHBDMA_REQ_N_A; +} + +static struct dma_chan *tegra_ahbdma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct tegra_ahbdma *tdma = ofdma->of_dma_data; + struct dma_chan *chan; + + chan = dma_get_any_slave_channel(&tdma->dma_dev); + if (!chan) + return NULL; + + to_ahbdma_chan(chan)->of_req_sel = dma_spec->args[0]; + to_ahbdma_chan(chan)->of_slave = true; + + return chan; +} + +static int tegra_ahbdma_init_hw(struct tegra_ahbdma *tdma, struct device *dev) +{ + int err; + + err = reset_control_assert(tdma->rst); + if (err) { + dev_err(dev, "Failed to assert reset: %d\n", err); + return err; + } + + err = clk_prepare_enable(tdma->clk); + if (err) { + dev_err(dev, "Failed to enable clock: %d\n", err); + return err; + } + + usleep_range(1000, 2000); + + err = reset_control_deassert(tdma->rst); + if (err) { + dev_err(dev, "Failed to deassert reset: %d\n", err); + return err; + } + + writel_relaxed(AHBDMA_CMD_ENABLE, tdma->regs + AHBDMA_CMD); + + writel_relaxed(AHBDMA_IRQ_ENB_CH(0) | + AHBDMA_IRQ_ENB_CH(1) | + AHBDMA_IRQ_ENB_CH(2) | + AHBDMA_IRQ_ENB_CH(3), + tdma->regs + AHBDMA_IRQ_ENB_MASK); + + return 0; +} + +static int tegra_ahbdma_probe(struct platform_device *pdev) +{ + struct dma_device *dma_dev; + struct tegra_ahbdma *tdma; + struct resource *res_regs; + unsigned int i; + int irq; + int err; + + tdma = devm_kzalloc(&pdev->dev, sizeof(*tdma), GFP_KERNEL); + if (!tdma) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ\n"); + return irq; + } + + err = devm_request_irq(&pdev->dev, irq, tegra_ahbdma_isr, 0, + dev_name(&pdev->dev), tdma); + if (err) { + dev_err(&pdev->dev, "Failed to request IRQ\n"); + return -ENODEV; + } + + res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_regs) + return -ENODEV; + + tdma->regs = devm_ioremap_resource(&pdev->dev, res_regs); + if (IS_ERR(tdma->regs)) + return PTR_ERR(tdma->regs); + + tdma->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(tdma->clk)) { + dev_err(&pdev->dev, "Failed to get AHB-DMA clock\n"); + return PTR_ERR(tdma->clk); + } + + tdma->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(tdma->rst)) { + dev_err(&pdev->dev, "Failed to get AHB-DMA reset\n"); + return PTR_ERR(tdma->rst); + } + + err = tegra_ahbdma_init_hw(tdma, &pdev->dev); + if (err) + return err; + + dma_dev = &tdma->dma_dev; + + INIT_LIST_HEAD(&dma_dev->channels); + + for (i = 0; i < ARRAY_SIZE(tdma->channels); i++) + tegra_ahbdma_init_channel(tdma, i); + + dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask); + dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask); + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); + + dma_dev->max_burst = 8; + dma_dev->directions = AHBDMA_DIRECTIONS; + dma_dev->src_addr_widths = AHBDMA_BUS_WIDTH; + dma_dev->dst_addr_widths = AHBDMA_BUS_WIDTH; + dma_dev->descriptor_reuse = true; + dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + dma_dev->device_free_chan_resources = tegra_ahbdma_free_chan_resources; + dma_dev->device_prep_slave_sg = tegra_ahbdma_prep_slave_sg; + dma_dev->device_prep_dma_cyclic = tegra_ahbdma_prep_dma_cyclic; + dma_dev->device_terminate_all = tegra_ahbdma_terminate_all; + dma_dev->device_issue_pending = tegra_ahbdma_issue_pending; + dma_dev->device_tx_status = tegra_ahbdma_tx_status; + dma_dev->device_config = tegra_ahbdma_config; + dma_dev->device_synchronize = tegra_ahbdma_synchronize; + dma_dev->dev = &pdev->dev; + + err = dma_async_device_register(dma_dev); + if (err) { + dev_err(&pdev->dev, "Device registration failed %d\n", err); + return err; + } + + err = of_dma_controller_register(pdev->dev.of_node, + tegra_ahbdma_of_xlate, tdma); + if (err) { + dev_err(&pdev->dev, "OF registration failed %d\n", err); + dma_async_device_unregister(dma_dev); + return err; + } + + platform_set_drvdata(pdev, tdma); + + return 0; +} + +static int tegra_ahbdma_remove(struct platform_device *pdev) +{ + struct tegra_ahbdma *tdma = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&tdma->dma_dev); + clk_disable_unprepare(tdma->clk); + + return 0; +} + +static const struct of_device_id tegra_ahbdma_of_match[] = { + { .compatible = "nvidia,tegra20-ahbdma" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_ahbdma_of_match); + +static struct platform_driver tegra_ahbdma_driver = { + .driver = { + .name = "tegra-ahbdma", + .of_match_table = tegra_ahbdma_of_match, + }, + .probe = tegra_ahbdma_probe, + .remove = tegra_ahbdma_remove, +}; +module_platform_driver(tegra_ahbdma_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra AHB DMA Controller driver"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_LICENSE("GPL"); From patchwork Tue Oct 3 23:58:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 821079 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; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="KBoUUYBq"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3y6GFr0jJvz9t2h for ; Wed, 4 Oct 2017 10:58:40 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751421AbdJCX6i (ORCPT ); Tue, 3 Oct 2017 19:58:38 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:56926 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751250AbdJCX6h (ORCPT ); Tue, 3 Oct 2017 19:58:37 -0400 Received: by mail-wm0-f67.google.com with SMTP id l68so6134082wmd.5; Tue, 03 Oct 2017 16:58:36 -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:in-reply-to:references :in-reply-to:references; bh=/m0W+z04lDwEp95axNbc0v7AH2x6zcwErvhjaa8BSDQ=; b=KBoUUYBqsFjsnaqQDh/Ems3Ndxu35ETa2ObZLa1/cCvQEUvarTJF02t8m9YbH9HQfB n6oORHtZVTmiWwO+7sfN5cYhY22hSyPoGZPkMLCWzjUxjTyf4ofR8/n1aulodxbbCxE4 S+pJioBo8zzxfdYpXepz8WvMei2GoYK7C0/DPnGiogxc3PqgL23uWf3XDnNn0Q0WH3MO Qcl2OGHJtXyRQ3dNDIrmo+sZKuqF9fXBDzGJrvwaLHqfIpuUaH6rfTUS4fR/pTt1lHke oHz9g0rcZikQP7rsr2Vd+11id72kdr2Fl2XH+8lf4gw3Peo2pKqXD4Ke8tVBsUD3GnaK IL8w== 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=/m0W+z04lDwEp95axNbc0v7AH2x6zcwErvhjaa8BSDQ=; b=Ra8t/Ms0B4MNJSiHWLspEqP6s6CIHgscCnz6kMygh4gW3Dj6PvDGA9yKYpQ506PMi3 LM//iIKZ6DLb0nM+jWuKwL7X5ZaNh1WltcZoR+zJU/wAVFEHNjNsLwFe2jKAcknBPk/p BMHCdTHRqGqxeo6YsBmOr9LenbCwza1fGBh9XfeXUQGiVUz9Sh11JCm0ucTDC5BboH3B iJOmWrTDdK4DW2Sc6vYfhEy9ttTX647Y1ryJADg2jJDV1vB5FuvcFDCS2CHIxfYJWF6e Ib7WXRqiv4X4anEbkMJIn18iaUBvAEePIhRgb3URr/f9gtIzmsRznzs7esFgunJczbHX 4LCQ== X-Gm-Message-State: AMCzsaU5ssRqF1UmP8mNKi3zWYw6ytHR/pXMqXlQuZEaRaQqfnRO+DQu d4p1L14QlKDWdtOT0rtBau8= X-Google-Smtp-Source: AOwi7QCQ3UmR0SHOj+yW1iRyzh1sqCvPbR8GuhpVqTmk7fIbLcJziCqqUDZXvTWWCsHzNItM/t2Vlg== X-Received: by 10.28.125.206 with SMTP id y197mr8263735wmc.85.1507075116380; Tue, 03 Oct 2017 16:58:36 -0700 (PDT) Received: from localhost.localdomain (ppp109-252-55-163.pppoe.spdop.ru. [109.252.55.163]) by smtp.gmail.com with ESMTPSA id r21sm8702808wmd.26.2017.10.03.16.58.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 Oct 2017 16:58:35 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Vinod Koul , Laxman Dewangan , Stephen Warren Cc: dmaengine@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH v2 3/3] ARM: dts: tegra: Add AHB DMA controller nodes Date: Wed, 4 Oct 2017 02:58:03 +0300 Message-Id: <558707e936a4cbedd2782ea23133aab06efc2ff2.1507073384.git.digetx@gmail.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Add AHB DMA controller nodes to Tegra20/30 DT's. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20.dtsi | 9 +++++++++ arch/arm/boot/dts/tegra30.dtsi | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 1b5d54b6c0cb..9839dd8e934f 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -200,6 +200,15 @@ reg = <0x60007000 0x1000>; }; + ahbdma: ahbdma@60008000 { + compatible = "nvidia,tegra20-ahbdma"; + reg = <0x60008000 0x2000>; + interrupts = ; + clocks = <&tegra_car TEGRA20_CLK_AHBDMA>; + resets = <&tegra_car 33>; + #dma-cells = <1>; + }; + apbdma: dma@6000a000 { compatible = "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1200>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 13960fda7471..0800d9a8c546 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -291,6 +291,15 @@ reg = <0x60007000 0x1000>; }; + ahbdma: ahbdma@60008000 { + compatible = "nvidia,tegra20-ahbdma"; + reg = <0x60008000 0x2000>; + interrupts = ; + clocks = <&tegra_car TEGRA30_CLK_AHBDMA>; + resets = <&tegra_car 33>; + #dma-cells = <1>; + }; + apbdma: dma@6000a000 { compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1400>;