* [PATCH 0/2] dmaengine: Add UniPhier XDMAC driver
@ 2019-12-18 0:56 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:56 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
Add support for UniPhier external DMA controller (XDMAC), that is implemented
in Pro4, Pro5, PXs2, LD11, LD20 and PXs3 SoCs.
Kunihiko Hayashi (2):
dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
.../devicetree/bindings/dma/uniphier-xdmac.txt | 86 +++
drivers/dma/Kconfig | 11 +
drivers/dma/Makefile | 1 +
drivers/dma/uniphier-xdmac.c | 620 +++++++++++++++++++++
4 files changed, 718 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
create mode 100644 drivers/dma/uniphier-xdmac.c
--
2.7.4
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 0/2] dmaengine: Add UniPhier XDMAC driver
@ 2019-12-18 0:56 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:56 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: devicetree, Kunihiko Hayashi, Masami Hiramatsu, linux-kernel,
Jassi Brar, dmaengine, linux-arm-kernel
Add support for UniPhier external DMA controller (XDMAC), that is implemented
in Pro4, Pro5, PXs2, LD11, LD20 and PXs3 SoCs.
Kunihiko Hayashi (2):
dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
.../devicetree/bindings/dma/uniphier-xdmac.txt | 86 +++
drivers/dma/Kconfig | 11 +
drivers/dma/Makefile | 1 +
drivers/dma/uniphier-xdmac.c | 620 +++++++++++++++++++++
4 files changed, 718 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
create mode 100644 drivers/dma/uniphier-xdmac.c
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
2019-12-18 0:56 ` Kunihiko Hayashi
@ 2019-12-18 0:56 ` Kunihiko Hayashi
-1 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:56 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
Add external DMA controller bindings implemented in Socionext UniPhier
SoCs.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
.../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
new file mode 100644
index 00000000..4e3927f
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
@@ -0,0 +1,86 @@
+Socionext UniPhier external DMA controller bindings
+
+This describes the devicetree bindings for an external DMA engine to perform
+memory-to-memory or peripheral-to-memory data transfer, implemented in
+Socionext UniPhier SoCs.
+
+* DMA controller
+
+Required properties:
+- compatible: Should be "socionext,uniphier-xdmac".
+- reg: Specifies offset and length of the register set for the device.
+- interrupts: An interrupt specifier associated with the DMA controller.
+- #dma-cells: Must be <2>. The first cell represents the channel index.
+ The second cell represents the factor for transfer request.
+ This is mentioned in DMA client section.
+- dma-channels : Number of DMA channels supported. Should be 16.
+
+Example:
+ xdmac: dma-controller@5fc10000 {
+ compatible = "socionext,uniphier-xdmac";
+ reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
+ interrupts = <0 188 4>;
+ #dma-cells = <2>;
+ dma-channels = <16>;
+ };
+
+* DMA client
+
+Required properties:
+- dmas: A list of DMA channel requests.
+- dma-names: Names of the requested channels corresponding to dmas.
+
+DMA clients must use the format described in the dma.txt file, using a two cell
+specifier for each channel.
+
+Each DMA request consists of 3 cells:
+ 1. A phandle pointing to the DMA controller
+ 2. Channel index
+ 3. Transfer request factor number, If no transfer factor, use 0.
+ The number is SoC-specific, and this should be specified with relation
+ to the device to use the DMA controller. The list of the factor number
+ can be found below.
+
+ 0x0 none
+ 0x8 UART ch0 Rx
+ 0x9 UART ch0 Tx
+ 0xa UART ch1 Rx
+ 0xb UART ch1 Tx
+ 0xc UART ch2 Rx
+ 0xd UART ch2 Tx
+ 0xe UART ch3 Rx
+ 0xf UART ch3 Tx
+ 0x14 SCSSI ch1 Rx
+ 0x15 SCSSI ch1 Tx
+ 0x16 SCSSI ch0 Rx
+ 0x17 SCSSI ch0 Tx
+ 0x18 SCSSI ch2 Rx
+ 0x19 SCSSI ch2 Tx
+ 0x1a SCSSI ch3 Rx
+ 0x1b SCSSI ch3 Tx
+ 0x21 I2C ch0 Rx
+ 0x22 I2C ch0 Tx
+ 0x23 I2C ch1 Rx
+ 0x24 I2C ch1 Tx
+ 0x25 I2C ch2 Rx
+ 0x26 I2C ch2 Tx
+ 0x27 I2C ch3 Rx
+ 0x28 I2C ch3 Tx
+ 0x29 I2C ch4 Rx
+ 0x2a I2C ch4 Tx
+ 0x2b I2C ch5 Rx
+ 0x2c I2C ch5 Tx
+ 0x2d I2C ch6 Rx
+ 0x2e I2C ch6 Tx
+
+Example:
+ spi3: spi@54006300 {
+ compatible = "socionext,uniphier-scssi";
+ reg = <0x54006300 0x100>;
+ interrupts = <0 39 4>;
+ clocks = <&peri_clk 14>;
+ resets = <&peri_rst 14>;
+
+ dmas = <&xdmac 0 0x1a>, <&xdmac 1 0x1b>;
+ dma-names = "rx", "tx";
+ };
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
@ 2019-12-18 0:56 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:56 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: devicetree, Kunihiko Hayashi, Masami Hiramatsu, linux-kernel,
Jassi Brar, dmaengine, linux-arm-kernel
Add external DMA controller bindings implemented in Socionext UniPhier
SoCs.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
.../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
new file mode 100644
index 00000000..4e3927f
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
@@ -0,0 +1,86 @@
+Socionext UniPhier external DMA controller bindings
+
+This describes the devicetree bindings for an external DMA engine to perform
+memory-to-memory or peripheral-to-memory data transfer, implemented in
+Socionext UniPhier SoCs.
+
+* DMA controller
+
+Required properties:
+- compatible: Should be "socionext,uniphier-xdmac".
+- reg: Specifies offset and length of the register set for the device.
+- interrupts: An interrupt specifier associated with the DMA controller.
+- #dma-cells: Must be <2>. The first cell represents the channel index.
+ The second cell represents the factor for transfer request.
+ This is mentioned in DMA client section.
+- dma-channels : Number of DMA channels supported. Should be 16.
+
+Example:
+ xdmac: dma-controller@5fc10000 {
+ compatible = "socionext,uniphier-xdmac";
+ reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
+ interrupts = <0 188 4>;
+ #dma-cells = <2>;
+ dma-channels = <16>;
+ };
+
+* DMA client
+
+Required properties:
+- dmas: A list of DMA channel requests.
+- dma-names: Names of the requested channels corresponding to dmas.
+
+DMA clients must use the format described in the dma.txt file, using a two cell
+specifier for each channel.
+
+Each DMA request consists of 3 cells:
+ 1. A phandle pointing to the DMA controller
+ 2. Channel index
+ 3. Transfer request factor number, If no transfer factor, use 0.
+ The number is SoC-specific, and this should be specified with relation
+ to the device to use the DMA controller. The list of the factor number
+ can be found below.
+
+ 0x0 none
+ 0x8 UART ch0 Rx
+ 0x9 UART ch0 Tx
+ 0xa UART ch1 Rx
+ 0xb UART ch1 Tx
+ 0xc UART ch2 Rx
+ 0xd UART ch2 Tx
+ 0xe UART ch3 Rx
+ 0xf UART ch3 Tx
+ 0x14 SCSSI ch1 Rx
+ 0x15 SCSSI ch1 Tx
+ 0x16 SCSSI ch0 Rx
+ 0x17 SCSSI ch0 Tx
+ 0x18 SCSSI ch2 Rx
+ 0x19 SCSSI ch2 Tx
+ 0x1a SCSSI ch3 Rx
+ 0x1b SCSSI ch3 Tx
+ 0x21 I2C ch0 Rx
+ 0x22 I2C ch0 Tx
+ 0x23 I2C ch1 Rx
+ 0x24 I2C ch1 Tx
+ 0x25 I2C ch2 Rx
+ 0x26 I2C ch2 Tx
+ 0x27 I2C ch3 Rx
+ 0x28 I2C ch3 Tx
+ 0x29 I2C ch4 Rx
+ 0x2a I2C ch4 Tx
+ 0x2b I2C ch5 Rx
+ 0x2c I2C ch5 Tx
+ 0x2d I2C ch6 Rx
+ 0x2e I2C ch6 Tx
+
+Example:
+ spi3: spi@54006300 {
+ compatible = "socionext,uniphier-scssi";
+ reg = <0x54006300 0x100>;
+ interrupts = <0 39 4>;
+ clocks = <&peri_clk 14>;
+ resets = <&peri_rst 14>;
+
+ dmas = <&xdmac 0 0x1a>, <&xdmac 1 0x1b>;
+ dma-names = "rx", "tx";
+ };
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
2019-12-18 0:56 ` Kunihiko Hayashi
@ 2019-12-18 0:57 ` Kunihiko Hayashi
-1 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:57 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
This adds external DMA controller driver implemented in Socionext
UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
Since this driver does not support the the way to transfer size
unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
dma_slave_config must be 1 to transfer arbitrary size,
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/dma/Kconfig | 11 +
drivers/dma/Makefile | 1 +
drivers/dma/uniphier-xdmac.c | 620 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 632 insertions(+)
create mode 100644 drivers/dma/uniphier-xdmac.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 7af874b..2d1cb5e 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -608,6 +608,17 @@ config UNIPHIER_MDMAC
UniPhier platform. This DMA controller is used as the external
DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
+config UNIPHIER_XDMAC
+ tristate "UniPhier XDMAC support"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Enable support for the XDMAC (external DMA controller) on the
+ UniPhier platform. This DMA controller can transfer data from
+ memory to memory, memory to peripheral and peripheral to memory.
+
config XGENE_DMA
tristate "APM X-Gene DMA support"
depends on ARCH_XGENE || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index f5ce866..6452468 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
+obj-$(CONFIG_UNIPHIER_XDMAC) += uniphier-xdmac.o
obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
obj-$(CONFIG_ZX_DMA) += zx_dma.o
obj-$(CONFIG_ST_FDMA) += st_fdma.o
diff --git a/drivers/dma/uniphier-xdmac.c b/drivers/dma/uniphier-xdmac.c
new file mode 100644
index 00000000..b21aa6a
--- /dev/null
+++ b/drivers/dma/uniphier-xdmac.c
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * External DMA controller driver for UniPhier SoCs
+ * Copyright 2019 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+#define XDMAC_CH_WIDTH 0x100
+
+#define XDMAC_TFA 0x08
+#define XDMAC_TFA_MCNT_MASK GENMASK(23, 16)
+#define XDMAC_TFA_MASK GENMASK(5, 0)
+#define XDMAC_SADM 0x10
+#define XDMAC_SADM_STW_MASK GENMASK(25, 24)
+#define XDMAC_SADM_SAM BIT(4)
+#define XDMAC_SADM_SAM_FIXED XDMAC_SADM_SAM
+#define XDMAC_SADM_SAM_INC 0
+#define XDMAC_DADM 0x14
+#define XDMAC_DADM_DTW_MASK XDMAC_SADM_STW_MASK
+#define XDMAC_DADM_DAM XDMAC_SADM_SAM
+#define XDMAC_DADM_DAM_FIXED XDMAC_SADM_SAM_FIXED
+#define XDMAC_DADM_DAM_INC XDMAC_SADM_SAM_INC
+#define XDMAC_EXSAD 0x18
+#define XDMAC_EXDAD 0x1c
+#define XDMAC_SAD 0x20
+#define XDMAC_DAD 0x24
+#define XDMAC_ITS 0x28
+#define XDMAC_ITS_MASK GENMASK(25, 0)
+#define XDMAC_TNUM 0x2c
+#define XDMAC_TNUM_MASK GENMASK(15, 0)
+#define XDMAC_TSS 0x30
+#define XDMAC_TSS_REQ BIT(0)
+#define XDMAC_IEN 0x34
+#define XDMAC_IEN_ERRIEN BIT(1)
+#define XDMAC_IEN_ENDIEN BIT(0)
+#define XDMAC_STAT 0x40
+#define XDMAC_STAT_TENF BIT(0)
+#define XDMAC_IR 0x44
+#define XDMAC_IR_ERRF BIT(1)
+#define XDMAC_IR_ENDF BIT(0)
+#define XDMAC_ID 0x48
+#define XDMAC_ID_ERRIDF BIT(1)
+#define XDMAC_ID_ENDIDF BIT(0)
+
+#define XDMAC_MAX_CHANS 16
+#define XDMAC_INTERVAL_CLKS 20
+#define XDMAC_MAX_WORDS XDMAC_TNUM_MASK
+
+/* cut lower bit for maintain alignment of maximum transfer size */
+#define XDMAC_MAX_WORD_SIZE (XDMAC_ITS_MASK & ~GENMASK(3, 0))
+
+#define UNIPHIER_XDMAC_BUSWIDTHS \
+ (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
+struct uniphier_xdmac_desc_node {
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 burst_size;
+ u32 nr_burst;
+};
+
+struct uniphier_xdmac_desc {
+ struct virt_dma_desc vd;
+
+ unsigned int nr_node;
+ unsigned int cur_node;
+ enum dma_transfer_direction dir;
+ struct uniphier_xdmac_desc_node nodes[0];
+};
+
+struct uniphier_xdmac_chan {
+ struct virt_dma_chan vc;
+ struct uniphier_xdmac_device *xdev;
+ struct uniphier_xdmac_desc *xd;
+ void __iomem *reg_ch_base;
+ struct dma_slave_config sconfig;
+ int id;
+ unsigned int req_factor;
+};
+
+struct uniphier_xdmac_device {
+ struct dma_device ddev;
+ void __iomem *reg_base;
+ int nr_chans;
+ struct uniphier_xdmac_chan channels[0];
+};
+
+static struct uniphier_xdmac_chan *
+to_uniphier_xdmac_chan(struct virt_dma_chan *vc)
+{
+ return container_of(vc, struct uniphier_xdmac_chan, vc);
+}
+
+static struct uniphier_xdmac_desc *
+to_uniphier_xdmac_desc(struct virt_dma_desc *vd)
+{
+ return container_of(vd, struct uniphier_xdmac_desc, vd);
+}
+
+/* xc->vc.lock must be held by caller */
+static struct uniphier_xdmac_desc *
+uniphier_xdmac_next_desc(struct uniphier_xdmac_chan *xc)
+{
+ struct virt_dma_desc *vd;
+
+ vd = vchan_next_desc(&xc->vc);
+ if (!vd)
+ return NULL;
+
+ list_del(&vd->node);
+
+ return to_uniphier_xdmac_desc(vd);
+}
+
+/* xc->vc.lock must be held by caller */
+static void uniphier_xdmac_chan_start(struct uniphier_xdmac_chan *xc,
+ struct uniphier_xdmac_desc *xd)
+{
+ u32 src_mode, src_addr, src_width;
+ u32 dst_mode, dst_addr, dst_width;
+ u32 val, its, tnum;
+ enum dma_slave_buswidth buswidth;
+
+ src_addr = xd->nodes[xd->cur_node].src;
+ dst_addr = xd->nodes[xd->cur_node].dst;
+ its = xd->nodes[xd->cur_node].burst_size;
+ tnum = xd->nodes[xd->cur_node].nr_burst;
+
+ /*
+ * The width of MEM side must be 4 or 8 bytes, that does not
+ * affect that of DEV side and transfer size.
+ */
+ if (xd->dir == DMA_DEV_TO_MEM) {
+ src_mode = XDMAC_SADM_SAM_FIXED;
+ buswidth = xc->sconfig.src_addr_width;
+ } else {
+ src_mode = XDMAC_SADM_SAM_INC;
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
+ }
+ src_width = FIELD_PREP(XDMAC_SADM_STW_MASK, __ffs(buswidth));
+
+ if (xd->dir == DMA_MEM_TO_DEV) {
+ dst_mode = XDMAC_DADM_DAM_FIXED;
+ buswidth = xc->sconfig.dst_addr_width;
+ } else {
+ dst_mode = XDMAC_DADM_DAM_INC;
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
+ }
+ dst_width = FIELD_PREP(XDMAC_DADM_DTW_MASK, __ffs(buswidth));
+
+ /* setup transfer factor */
+ val = FIELD_PREP(XDMAC_TFA_MCNT_MASK, XDMAC_INTERVAL_CLKS);
+ val |= FIELD_PREP(XDMAC_TFA_MASK, xc->req_factor);
+ writel(val, xc->reg_ch_base + XDMAC_TFA);
+
+ /* setup the channel */
+ writel(lower_32_bits(src_addr), xc->reg_ch_base + XDMAC_SAD);
+ writel(upper_32_bits(src_addr), xc->reg_ch_base + XDMAC_EXSAD);
+
+ writel(lower_32_bits(dst_addr), xc->reg_ch_base + XDMAC_DAD);
+ writel(upper_32_bits(dst_addr), xc->reg_ch_base + XDMAC_EXDAD);
+
+ src_mode |= src_width;
+ dst_mode |= dst_width;
+ writel(src_mode, xc->reg_ch_base + XDMAC_SADM);
+ writel(dst_mode, xc->reg_ch_base + XDMAC_DADM);
+
+ writel(its, xc->reg_ch_base + XDMAC_ITS);
+ writel(tnum, xc->reg_ch_base + XDMAC_TNUM);
+
+ /* enable interrupt */
+ writel(XDMAC_IEN_ENDIEN | XDMAC_IEN_ERRIEN,
+ xc->reg_ch_base + XDMAC_IEN);
+
+ /* start XDMAC */
+ val = readl(xc->reg_ch_base + XDMAC_TSS);
+ val |= XDMAC_TSS_REQ;
+ writel(val, xc->reg_ch_base + XDMAC_TSS);
+}
+
+/* xc->vc.lock must be held by caller */
+static int uniphier_xdmac_chan_stop(struct uniphier_xdmac_chan *xc)
+{
+ u32 val;
+
+ /* disable interrupt */
+ val = readl(xc->reg_ch_base + XDMAC_IEN);
+ val &= ~(XDMAC_IEN_ENDIEN | XDMAC_IEN_ERRIEN);
+ writel(val, xc->reg_ch_base + XDMAC_IEN);
+
+ /* stop XDMAC */
+ val = readl(xc->reg_ch_base + XDMAC_TSS);
+ val &= ~XDMAC_TSS_REQ;
+ writel(0, xc->reg_ch_base + XDMAC_TSS);
+
+ /* wait until transfer is stopped */
+ return readl_poll_timeout(xc->reg_ch_base + XDMAC_STAT, val,
+ !(val & XDMAC_STAT_TENF), 100, 1000);
+}
+
+/* xc->vc.lock must be held by caller */
+static void uniphier_xdmac_start(struct uniphier_xdmac_chan *xc)
+{
+ struct uniphier_xdmac_desc *xd;
+
+ xd = uniphier_xdmac_next_desc(xc);
+ if (xd)
+ uniphier_xdmac_chan_start(xc, xd);
+
+ /* set desc to chan regardless of xd is null */
+ xc->xd = xd;
+}
+
+static void uniphier_xdmac_chan_irq(struct uniphier_xdmac_chan *xc)
+{
+ u32 stat;
+ int ret;
+
+ spin_lock(&xc->vc.lock);
+
+ stat = readl(xc->reg_ch_base + XDMAC_ID);
+
+ if (stat & XDMAC_ID_ERRIDF) {
+ ret = uniphier_xdmac_chan_stop(xc);
+ if (ret)
+ dev_err(xc->xdev->ddev.dev,
+ "DMA transfer error with aborting issue\n");
+ else
+ dev_err(xc->xdev->ddev.dev,
+ "DMA transfer error\n");
+
+ } else if ((stat & XDMAC_ID_ENDIDF) && xc->xd) {
+ xc->xd->cur_node++;
+ if (xc->xd->cur_node >= xc->xd->nr_node) {
+ vchan_cookie_complete(&xc->xd->vd);
+ uniphier_xdmac_start(xc);
+ } else {
+ uniphier_xdmac_chan_start(xc, xc->xd);
+ }
+ }
+
+ /* write bits to clear */
+ writel(stat, xc->reg_ch_base + XDMAC_IR);
+
+ spin_unlock(&xc->vc.lock);
+}
+
+static irqreturn_t uniphier_xdmac_irq_handler(int irq, void *dev_id)
+{
+ struct uniphier_xdmac_device *xdev = dev_id;
+ int i;
+
+ for (i = 0; i < xdev->nr_chans; i++)
+ uniphier_xdmac_chan_irq(&xdev->channels[i]);
+
+ return IRQ_HANDLED;
+}
+
+static void uniphier_xdmac_free_chan_resources(struct dma_chan *chan)
+{
+ vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+static struct dma_async_tx_descriptor *
+uniphier_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
+ dma_addr_t src, size_t len, unsigned long flags)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_desc *xd;
+ unsigned int nr = 1;
+ size_t burst_size, tlen;
+ int i;
+
+ if (len > XDMAC_MAX_WORD_SIZE * XDMAC_MAX_WORDS)
+ return NULL;
+
+ if ((len > XDMAC_MAX_WORD_SIZE) && (len % XDMAC_MAX_WORD_SIZE))
+ nr++;
+
+ xd = kzalloc(struct_size(xd, nodes, nr), GFP_NOWAIT);
+ if (!xd)
+ return NULL;
+
+ for (i = 0; i < nr; i++) {
+ burst_size = min_t(size_t, len, XDMAC_MAX_WORD_SIZE);
+ xd->nodes[i].src = src;
+ xd->nodes[i].dst = dst;
+ xd->nodes[i].burst_size = burst_size;
+ xd->nodes[i].nr_burst = len / burst_size;
+ tlen = rounddown(len, burst_size);
+ src += tlen;
+ dst += tlen;
+ len -= tlen;
+ }
+
+ xd->dir = DMA_MEM_TO_MEM;
+ xd->nr_node = nr;
+ xd->cur_node = 0;
+
+ return vchan_tx_prep(vc, &xd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *
+uniphier_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ struct uniphier_xdmac_desc *xd;
+ struct scatterlist *sg;
+ enum dma_slave_buswidth buswidth;
+ u32 maxburst;
+ int i;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ buswidth = xc->sconfig.src_addr_width;
+ maxburst = xc->sconfig.src_maxburst;
+ } else {
+ buswidth = xc->sconfig.dst_addr_width;
+ maxburst = xc->sconfig.dst_maxburst;
+ }
+
+ if (!maxburst)
+ maxburst = 1;
+ if (maxburst > xc->xdev->ddev.max_burst) {
+ dev_err(xc->xdev->ddev.dev,
+ "Exceed maximum number of burst words\n");
+ return NULL;
+ }
+
+ xd = kzalloc(struct_size(xd, nodes, sg_len), GFP_NOWAIT);
+ if (!xd)
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ xd->nodes[i].src = (direction == DMA_DEV_TO_MEM)
+ ? xc->sconfig.src_addr : sg_dma_address(sg);
+ xd->nodes[i].dst = (direction == DMA_MEM_TO_DEV)
+ ? xc->sconfig.dst_addr : sg_dma_address(sg);
+ xd->nodes[i].burst_size = maxburst * buswidth;
+ xd->nodes[i].nr_burst =
+ sg_dma_len(sg) / xd->nodes[i].burst_size;
+
+ /*
+ * Currently transfer that size doesn't align the unit size
+ * (the number of burst words * bus-width) is not allowed,
+ * because the driver does not support the way to transfer
+ * residue size. As a matter of fact, in order to transfer
+ * arbitrary size, 'src_maxburst' or 'dst_maxburst' of
+ * dma_slave_config must be 1.
+ */
+ if (sg_dma_len(sg) % xd->nodes[i].burst_size) {
+ dev_err(xc->xdev->ddev.dev,
+ "Unaligned transfer size: %d", sg_dma_len(sg));
+ kfree(xd);
+ return NULL;
+ }
+
+ if (xd->nodes[i].nr_burst > XDMAC_MAX_WORDS) {
+ dev_err(xc->xdev->ddev.dev,
+ "Exceed maximum transfer size");
+ kfree(xd);
+ return NULL;
+ }
+ }
+
+ xd->dir = direction;
+ xd->nr_node = sg_len;
+ xd->cur_node = 0;
+
+ return vchan_tx_prep(vc, &xd->vd, flags);
+}
+
+static int uniphier_xdmac_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+
+ memcpy(&xc->sconfig, config, sizeof(*config));
+
+ return 0;
+}
+
+static int uniphier_xdmac_terminate_all(struct dma_chan *chan)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ unsigned long flags;
+ int ret = 0;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&vc->lock, flags);
+
+ if (xc->xd) {
+ vchan_terminate_vdesc(&xc->xd->vd);
+ xc->xd = NULL;
+ ret = uniphier_xdmac_chan_stop(xc);
+ }
+
+ vchan_get_all_descriptors(vc, &head);
+
+ spin_unlock_irqrestore(&vc->lock, flags);
+
+ vchan_dma_desc_free_list(vc, &head);
+
+ return ret;
+}
+
+static void uniphier_xdmac_synchronize(struct dma_chan *chan)
+{
+ vchan_synchronize(to_virt_chan(chan));
+}
+
+static void uniphier_xdmac_issue_pending(struct dma_chan *chan)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vc->lock, flags);
+
+ if (vchan_issue_pending(vc) && !xc->xd)
+ uniphier_xdmac_start(xc);
+
+ spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void uniphier_xdmac_desc_free(struct virt_dma_desc *vd)
+{
+ kfree(to_uniphier_xdmac_desc(vd));
+}
+
+static int uniphier_xdmac_chan_init(struct uniphier_xdmac_device *xdev,
+ int ch)
+{
+ struct uniphier_xdmac_chan *xc = &xdev->channels[ch];
+
+ xc->xdev = xdev;
+ xc->reg_ch_base = xdev->reg_base + XDMAC_CH_WIDTH * ch;
+ xc->vc.desc_free = uniphier_xdmac_desc_free;
+
+ vchan_init(&xc->vc, &xdev->ddev);
+
+ return 0;
+}
+
+static struct dma_chan *of_dma_uniphier_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct uniphier_xdmac_device *xdev = ofdma->of_dma_data;
+ int chan_id = dma_spec->args[0];
+
+ if (chan_id >= xdev->nr_chans)
+ return NULL;
+
+ xdev->channels[chan_id].id = chan_id;
+ xdev->channels[chan_id].req_factor = dma_spec->args[1];
+
+ return dma_get_slave_channel(&xdev->channels[chan_id].vc.chan);
+}
+
+static int uniphier_xdmac_probe(struct platform_device *pdev)
+{
+ struct uniphier_xdmac_device *xdev;
+ struct device *dev = &pdev->dev;
+ struct dma_device *ddev;
+ int irq;
+ int nr_chans;
+ int i, ret;
+
+ if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
+ return -EINVAL;
+ if (nr_chans > XDMAC_MAX_CHANS)
+ nr_chans = XDMAC_MAX_CHANS;
+
+ xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
+ GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->nr_chans = nr_chans;
+ xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(xdev->reg_base))
+ return PTR_ERR(xdev->reg_base);
+
+ ddev = &xdev->ddev;
+ ddev->dev = dev;
+ dma_cap_zero(ddev->cap_mask);
+ dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
+ dma_cap_set(DMA_SLAVE, ddev->cap_mask);
+ ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
+ ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
+ ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
+ BIT(DMA_MEM_TO_MEM);
+ ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ ddev->max_burst = XDMAC_MAX_WORDS;
+ ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
+ ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
+ ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
+ ddev->device_config = uniphier_xdmac_slave_config;
+ ddev->device_terminate_all = uniphier_xdmac_terminate_all;
+ ddev->device_synchronize = uniphier_xdmac_synchronize;
+ ddev->device_tx_status = dma_cookie_status;
+ ddev->device_issue_pending = uniphier_xdmac_issue_pending;
+ INIT_LIST_HEAD(&ddev->channels);
+
+ for (i = 0; i < nr_chans; i++) {
+ ret = uniphier_xdmac_chan_init(xdev, i);
+ if (ret) {
+ dev_err(dev,
+ "Failed to initialize XDMAC channel %d\n", i);
+ return ret;
+ }
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "Failed to get IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, uniphier_xdmac_irq_handler,
+ IRQF_SHARED, "xdmac", xdev);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ\n");
+ return ret;
+ }
+
+ ret = dma_async_device_register(ddev);
+ if (ret) {
+ dev_err(dev, "Failed to register XDMA device\n");
+ return ret;
+ }
+
+ ret = of_dma_controller_register(dev->of_node,
+ of_dma_uniphier_xlate, xdev);
+ if (ret) {
+ dev_err(dev, "Failed to register XDMA controller\n");
+ goto out_unregister_dmac;
+ }
+
+ platform_set_drvdata(pdev, xdev);
+
+ dev_info(&pdev->dev, "UniPhier XDMAC driver (%d channels)\n",
+ nr_chans);
+
+ return 0;
+
+out_unregister_dmac:
+ dma_async_device_unregister(ddev);
+
+ return ret;
+}
+
+static int uniphier_xdmac_remove(struct platform_device *pdev)
+{
+ struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
+ struct dma_device *ddev = &xdev->ddev;
+ struct dma_chan *chan;
+ int ret;
+
+ /*
+ * Before reaching here, almost all descriptors have been freed by the
+ * ->device_free_chan_resources() hook. However, each channel might
+ * be still holding one descriptor that was on-flight at that moment.
+ * Terminate it to make sure this hardware is no longer running. Then,
+ * free the channel resources once again to avoid memory leak.
+ */
+ list_for_each_entry(chan, &ddev->channels, device_node) {
+ ret = dmaengine_terminate_sync(chan);
+ if (ret)
+ return ret;
+ uniphier_xdmac_free_chan_resources(chan);
+ }
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(ddev);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_xdmac_match[] = {
+ { .compatible = "socionext,uniphier-xdmac" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_xdmac_match);
+
+static struct platform_driver uniphier_xdmac_driver = {
+ .probe = uniphier_xdmac_probe,
+ .remove = uniphier_xdmac_remove,
+ .driver = {
+ .name = "uniphier-xdmac",
+ .of_match_table = uniphier_xdmac_match,
+ },
+};
+module_platform_driver(uniphier_xdmac_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier external DMA controller driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
@ 2019-12-18 0:57 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2019-12-18 0:57 UTC (permalink / raw)
To: Vinod Koul, Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland
Cc: devicetree, Kunihiko Hayashi, Masami Hiramatsu, linux-kernel,
Jassi Brar, dmaengine, linux-arm-kernel
This adds external DMA controller driver implemented in Socionext
UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
Since this driver does not support the the way to transfer size
unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
dma_slave_config must be 1 to transfer arbitrary size,
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/dma/Kconfig | 11 +
drivers/dma/Makefile | 1 +
drivers/dma/uniphier-xdmac.c | 620 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 632 insertions(+)
create mode 100644 drivers/dma/uniphier-xdmac.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 7af874b..2d1cb5e 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -608,6 +608,17 @@ config UNIPHIER_MDMAC
UniPhier platform. This DMA controller is used as the external
DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
+config UNIPHIER_XDMAC
+ tristate "UniPhier XDMAC support"
+ depends on ARCH_UNIPHIER || COMPILE_TEST
+ depends on OF
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Enable support for the XDMAC (external DMA controller) on the
+ UniPhier platform. This DMA controller can transfer data from
+ memory to memory, memory to peripheral and peripheral to memory.
+
config XGENE_DMA
tristate "APM X-Gene DMA support"
depends on ARCH_XGENE || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index f5ce866..6452468 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.o
obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
+obj-$(CONFIG_UNIPHIER_XDMAC) += uniphier-xdmac.o
obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
obj-$(CONFIG_ZX_DMA) += zx_dma.o
obj-$(CONFIG_ST_FDMA) += st_fdma.o
diff --git a/drivers/dma/uniphier-xdmac.c b/drivers/dma/uniphier-xdmac.c
new file mode 100644
index 00000000..b21aa6a
--- /dev/null
+++ b/drivers/dma/uniphier-xdmac.c
@@ -0,0 +1,620 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * External DMA controller driver for UniPhier SoCs
+ * Copyright 2019 Socionext Inc.
+ * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+#define XDMAC_CH_WIDTH 0x100
+
+#define XDMAC_TFA 0x08
+#define XDMAC_TFA_MCNT_MASK GENMASK(23, 16)
+#define XDMAC_TFA_MASK GENMASK(5, 0)
+#define XDMAC_SADM 0x10
+#define XDMAC_SADM_STW_MASK GENMASK(25, 24)
+#define XDMAC_SADM_SAM BIT(4)
+#define XDMAC_SADM_SAM_FIXED XDMAC_SADM_SAM
+#define XDMAC_SADM_SAM_INC 0
+#define XDMAC_DADM 0x14
+#define XDMAC_DADM_DTW_MASK XDMAC_SADM_STW_MASK
+#define XDMAC_DADM_DAM XDMAC_SADM_SAM
+#define XDMAC_DADM_DAM_FIXED XDMAC_SADM_SAM_FIXED
+#define XDMAC_DADM_DAM_INC XDMAC_SADM_SAM_INC
+#define XDMAC_EXSAD 0x18
+#define XDMAC_EXDAD 0x1c
+#define XDMAC_SAD 0x20
+#define XDMAC_DAD 0x24
+#define XDMAC_ITS 0x28
+#define XDMAC_ITS_MASK GENMASK(25, 0)
+#define XDMAC_TNUM 0x2c
+#define XDMAC_TNUM_MASK GENMASK(15, 0)
+#define XDMAC_TSS 0x30
+#define XDMAC_TSS_REQ BIT(0)
+#define XDMAC_IEN 0x34
+#define XDMAC_IEN_ERRIEN BIT(1)
+#define XDMAC_IEN_ENDIEN BIT(0)
+#define XDMAC_STAT 0x40
+#define XDMAC_STAT_TENF BIT(0)
+#define XDMAC_IR 0x44
+#define XDMAC_IR_ERRF BIT(1)
+#define XDMAC_IR_ENDF BIT(0)
+#define XDMAC_ID 0x48
+#define XDMAC_ID_ERRIDF BIT(1)
+#define XDMAC_ID_ENDIDF BIT(0)
+
+#define XDMAC_MAX_CHANS 16
+#define XDMAC_INTERVAL_CLKS 20
+#define XDMAC_MAX_WORDS XDMAC_TNUM_MASK
+
+/* cut lower bit for maintain alignment of maximum transfer size */
+#define XDMAC_MAX_WORD_SIZE (XDMAC_ITS_MASK & ~GENMASK(3, 0))
+
+#define UNIPHIER_XDMAC_BUSWIDTHS \
+ (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
+struct uniphier_xdmac_desc_node {
+ dma_addr_t src;
+ dma_addr_t dst;
+ u32 burst_size;
+ u32 nr_burst;
+};
+
+struct uniphier_xdmac_desc {
+ struct virt_dma_desc vd;
+
+ unsigned int nr_node;
+ unsigned int cur_node;
+ enum dma_transfer_direction dir;
+ struct uniphier_xdmac_desc_node nodes[0];
+};
+
+struct uniphier_xdmac_chan {
+ struct virt_dma_chan vc;
+ struct uniphier_xdmac_device *xdev;
+ struct uniphier_xdmac_desc *xd;
+ void __iomem *reg_ch_base;
+ struct dma_slave_config sconfig;
+ int id;
+ unsigned int req_factor;
+};
+
+struct uniphier_xdmac_device {
+ struct dma_device ddev;
+ void __iomem *reg_base;
+ int nr_chans;
+ struct uniphier_xdmac_chan channels[0];
+};
+
+static struct uniphier_xdmac_chan *
+to_uniphier_xdmac_chan(struct virt_dma_chan *vc)
+{
+ return container_of(vc, struct uniphier_xdmac_chan, vc);
+}
+
+static struct uniphier_xdmac_desc *
+to_uniphier_xdmac_desc(struct virt_dma_desc *vd)
+{
+ return container_of(vd, struct uniphier_xdmac_desc, vd);
+}
+
+/* xc->vc.lock must be held by caller */
+static struct uniphier_xdmac_desc *
+uniphier_xdmac_next_desc(struct uniphier_xdmac_chan *xc)
+{
+ struct virt_dma_desc *vd;
+
+ vd = vchan_next_desc(&xc->vc);
+ if (!vd)
+ return NULL;
+
+ list_del(&vd->node);
+
+ return to_uniphier_xdmac_desc(vd);
+}
+
+/* xc->vc.lock must be held by caller */
+static void uniphier_xdmac_chan_start(struct uniphier_xdmac_chan *xc,
+ struct uniphier_xdmac_desc *xd)
+{
+ u32 src_mode, src_addr, src_width;
+ u32 dst_mode, dst_addr, dst_width;
+ u32 val, its, tnum;
+ enum dma_slave_buswidth buswidth;
+
+ src_addr = xd->nodes[xd->cur_node].src;
+ dst_addr = xd->nodes[xd->cur_node].dst;
+ its = xd->nodes[xd->cur_node].burst_size;
+ tnum = xd->nodes[xd->cur_node].nr_burst;
+
+ /*
+ * The width of MEM side must be 4 or 8 bytes, that does not
+ * affect that of DEV side and transfer size.
+ */
+ if (xd->dir == DMA_DEV_TO_MEM) {
+ src_mode = XDMAC_SADM_SAM_FIXED;
+ buswidth = xc->sconfig.src_addr_width;
+ } else {
+ src_mode = XDMAC_SADM_SAM_INC;
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
+ }
+ src_width = FIELD_PREP(XDMAC_SADM_STW_MASK, __ffs(buswidth));
+
+ if (xd->dir == DMA_MEM_TO_DEV) {
+ dst_mode = XDMAC_DADM_DAM_FIXED;
+ buswidth = xc->sconfig.dst_addr_width;
+ } else {
+ dst_mode = XDMAC_DADM_DAM_INC;
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
+ }
+ dst_width = FIELD_PREP(XDMAC_DADM_DTW_MASK, __ffs(buswidth));
+
+ /* setup transfer factor */
+ val = FIELD_PREP(XDMAC_TFA_MCNT_MASK, XDMAC_INTERVAL_CLKS);
+ val |= FIELD_PREP(XDMAC_TFA_MASK, xc->req_factor);
+ writel(val, xc->reg_ch_base + XDMAC_TFA);
+
+ /* setup the channel */
+ writel(lower_32_bits(src_addr), xc->reg_ch_base + XDMAC_SAD);
+ writel(upper_32_bits(src_addr), xc->reg_ch_base + XDMAC_EXSAD);
+
+ writel(lower_32_bits(dst_addr), xc->reg_ch_base + XDMAC_DAD);
+ writel(upper_32_bits(dst_addr), xc->reg_ch_base + XDMAC_EXDAD);
+
+ src_mode |= src_width;
+ dst_mode |= dst_width;
+ writel(src_mode, xc->reg_ch_base + XDMAC_SADM);
+ writel(dst_mode, xc->reg_ch_base + XDMAC_DADM);
+
+ writel(its, xc->reg_ch_base + XDMAC_ITS);
+ writel(tnum, xc->reg_ch_base + XDMAC_TNUM);
+
+ /* enable interrupt */
+ writel(XDMAC_IEN_ENDIEN | XDMAC_IEN_ERRIEN,
+ xc->reg_ch_base + XDMAC_IEN);
+
+ /* start XDMAC */
+ val = readl(xc->reg_ch_base + XDMAC_TSS);
+ val |= XDMAC_TSS_REQ;
+ writel(val, xc->reg_ch_base + XDMAC_TSS);
+}
+
+/* xc->vc.lock must be held by caller */
+static int uniphier_xdmac_chan_stop(struct uniphier_xdmac_chan *xc)
+{
+ u32 val;
+
+ /* disable interrupt */
+ val = readl(xc->reg_ch_base + XDMAC_IEN);
+ val &= ~(XDMAC_IEN_ENDIEN | XDMAC_IEN_ERRIEN);
+ writel(val, xc->reg_ch_base + XDMAC_IEN);
+
+ /* stop XDMAC */
+ val = readl(xc->reg_ch_base + XDMAC_TSS);
+ val &= ~XDMAC_TSS_REQ;
+ writel(0, xc->reg_ch_base + XDMAC_TSS);
+
+ /* wait until transfer is stopped */
+ return readl_poll_timeout(xc->reg_ch_base + XDMAC_STAT, val,
+ !(val & XDMAC_STAT_TENF), 100, 1000);
+}
+
+/* xc->vc.lock must be held by caller */
+static void uniphier_xdmac_start(struct uniphier_xdmac_chan *xc)
+{
+ struct uniphier_xdmac_desc *xd;
+
+ xd = uniphier_xdmac_next_desc(xc);
+ if (xd)
+ uniphier_xdmac_chan_start(xc, xd);
+
+ /* set desc to chan regardless of xd is null */
+ xc->xd = xd;
+}
+
+static void uniphier_xdmac_chan_irq(struct uniphier_xdmac_chan *xc)
+{
+ u32 stat;
+ int ret;
+
+ spin_lock(&xc->vc.lock);
+
+ stat = readl(xc->reg_ch_base + XDMAC_ID);
+
+ if (stat & XDMAC_ID_ERRIDF) {
+ ret = uniphier_xdmac_chan_stop(xc);
+ if (ret)
+ dev_err(xc->xdev->ddev.dev,
+ "DMA transfer error with aborting issue\n");
+ else
+ dev_err(xc->xdev->ddev.dev,
+ "DMA transfer error\n");
+
+ } else if ((stat & XDMAC_ID_ENDIDF) && xc->xd) {
+ xc->xd->cur_node++;
+ if (xc->xd->cur_node >= xc->xd->nr_node) {
+ vchan_cookie_complete(&xc->xd->vd);
+ uniphier_xdmac_start(xc);
+ } else {
+ uniphier_xdmac_chan_start(xc, xc->xd);
+ }
+ }
+
+ /* write bits to clear */
+ writel(stat, xc->reg_ch_base + XDMAC_IR);
+
+ spin_unlock(&xc->vc.lock);
+}
+
+static irqreturn_t uniphier_xdmac_irq_handler(int irq, void *dev_id)
+{
+ struct uniphier_xdmac_device *xdev = dev_id;
+ int i;
+
+ for (i = 0; i < xdev->nr_chans; i++)
+ uniphier_xdmac_chan_irq(&xdev->channels[i]);
+
+ return IRQ_HANDLED;
+}
+
+static void uniphier_xdmac_free_chan_resources(struct dma_chan *chan)
+{
+ vchan_free_chan_resources(to_virt_chan(chan));
+}
+
+static struct dma_async_tx_descriptor *
+uniphier_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
+ dma_addr_t src, size_t len, unsigned long flags)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_desc *xd;
+ unsigned int nr = 1;
+ size_t burst_size, tlen;
+ int i;
+
+ if (len > XDMAC_MAX_WORD_SIZE * XDMAC_MAX_WORDS)
+ return NULL;
+
+ if ((len > XDMAC_MAX_WORD_SIZE) && (len % XDMAC_MAX_WORD_SIZE))
+ nr++;
+
+ xd = kzalloc(struct_size(xd, nodes, nr), GFP_NOWAIT);
+ if (!xd)
+ return NULL;
+
+ for (i = 0; i < nr; i++) {
+ burst_size = min_t(size_t, len, XDMAC_MAX_WORD_SIZE);
+ xd->nodes[i].src = src;
+ xd->nodes[i].dst = dst;
+ xd->nodes[i].burst_size = burst_size;
+ xd->nodes[i].nr_burst = len / burst_size;
+ tlen = rounddown(len, burst_size);
+ src += tlen;
+ dst += tlen;
+ len -= tlen;
+ }
+
+ xd->dir = DMA_MEM_TO_MEM;
+ xd->nr_node = nr;
+ xd->cur_node = 0;
+
+ return vchan_tx_prep(vc, &xd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *
+uniphier_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len,
+ enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ struct uniphier_xdmac_desc *xd;
+ struct scatterlist *sg;
+ enum dma_slave_buswidth buswidth;
+ u32 maxburst;
+ int i;
+
+ if (!is_slave_direction(direction))
+ return NULL;
+
+ if (direction == DMA_DEV_TO_MEM) {
+ buswidth = xc->sconfig.src_addr_width;
+ maxburst = xc->sconfig.src_maxburst;
+ } else {
+ buswidth = xc->sconfig.dst_addr_width;
+ maxburst = xc->sconfig.dst_maxburst;
+ }
+
+ if (!maxburst)
+ maxburst = 1;
+ if (maxburst > xc->xdev->ddev.max_burst) {
+ dev_err(xc->xdev->ddev.dev,
+ "Exceed maximum number of burst words\n");
+ return NULL;
+ }
+
+ xd = kzalloc(struct_size(xd, nodes, sg_len), GFP_NOWAIT);
+ if (!xd)
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ xd->nodes[i].src = (direction == DMA_DEV_TO_MEM)
+ ? xc->sconfig.src_addr : sg_dma_address(sg);
+ xd->nodes[i].dst = (direction == DMA_MEM_TO_DEV)
+ ? xc->sconfig.dst_addr : sg_dma_address(sg);
+ xd->nodes[i].burst_size = maxburst * buswidth;
+ xd->nodes[i].nr_burst =
+ sg_dma_len(sg) / xd->nodes[i].burst_size;
+
+ /*
+ * Currently transfer that size doesn't align the unit size
+ * (the number of burst words * bus-width) is not allowed,
+ * because the driver does not support the way to transfer
+ * residue size. As a matter of fact, in order to transfer
+ * arbitrary size, 'src_maxburst' or 'dst_maxburst' of
+ * dma_slave_config must be 1.
+ */
+ if (sg_dma_len(sg) % xd->nodes[i].burst_size) {
+ dev_err(xc->xdev->ddev.dev,
+ "Unaligned transfer size: %d", sg_dma_len(sg));
+ kfree(xd);
+ return NULL;
+ }
+
+ if (xd->nodes[i].nr_burst > XDMAC_MAX_WORDS) {
+ dev_err(xc->xdev->ddev.dev,
+ "Exceed maximum transfer size");
+ kfree(xd);
+ return NULL;
+ }
+ }
+
+ xd->dir = direction;
+ xd->nr_node = sg_len;
+ xd->cur_node = 0;
+
+ return vchan_tx_prep(vc, &xd->vd, flags);
+}
+
+static int uniphier_xdmac_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+
+ memcpy(&xc->sconfig, config, sizeof(*config));
+
+ return 0;
+}
+
+static int uniphier_xdmac_terminate_all(struct dma_chan *chan)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ unsigned long flags;
+ int ret = 0;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&vc->lock, flags);
+
+ if (xc->xd) {
+ vchan_terminate_vdesc(&xc->xd->vd);
+ xc->xd = NULL;
+ ret = uniphier_xdmac_chan_stop(xc);
+ }
+
+ vchan_get_all_descriptors(vc, &head);
+
+ spin_unlock_irqrestore(&vc->lock, flags);
+
+ vchan_dma_desc_free_list(vc, &head);
+
+ return ret;
+}
+
+static void uniphier_xdmac_synchronize(struct dma_chan *chan)
+{
+ vchan_synchronize(to_virt_chan(chan));
+}
+
+static void uniphier_xdmac_issue_pending(struct dma_chan *chan)
+{
+ struct virt_dma_chan *vc = to_virt_chan(chan);
+ struct uniphier_xdmac_chan *xc = to_uniphier_xdmac_chan(vc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&vc->lock, flags);
+
+ if (vchan_issue_pending(vc) && !xc->xd)
+ uniphier_xdmac_start(xc);
+
+ spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void uniphier_xdmac_desc_free(struct virt_dma_desc *vd)
+{
+ kfree(to_uniphier_xdmac_desc(vd));
+}
+
+static int uniphier_xdmac_chan_init(struct uniphier_xdmac_device *xdev,
+ int ch)
+{
+ struct uniphier_xdmac_chan *xc = &xdev->channels[ch];
+
+ xc->xdev = xdev;
+ xc->reg_ch_base = xdev->reg_base + XDMAC_CH_WIDTH * ch;
+ xc->vc.desc_free = uniphier_xdmac_desc_free;
+
+ vchan_init(&xc->vc, &xdev->ddev);
+
+ return 0;
+}
+
+static struct dma_chan *of_dma_uniphier_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct uniphier_xdmac_device *xdev = ofdma->of_dma_data;
+ int chan_id = dma_spec->args[0];
+
+ if (chan_id >= xdev->nr_chans)
+ return NULL;
+
+ xdev->channels[chan_id].id = chan_id;
+ xdev->channels[chan_id].req_factor = dma_spec->args[1];
+
+ return dma_get_slave_channel(&xdev->channels[chan_id].vc.chan);
+}
+
+static int uniphier_xdmac_probe(struct platform_device *pdev)
+{
+ struct uniphier_xdmac_device *xdev;
+ struct device *dev = &pdev->dev;
+ struct dma_device *ddev;
+ int irq;
+ int nr_chans;
+ int i, ret;
+
+ if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
+ return -EINVAL;
+ if (nr_chans > XDMAC_MAX_CHANS)
+ nr_chans = XDMAC_MAX_CHANS;
+
+ xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
+ GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->nr_chans = nr_chans;
+ xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(xdev->reg_base))
+ return PTR_ERR(xdev->reg_base);
+
+ ddev = &xdev->ddev;
+ ddev->dev = dev;
+ dma_cap_zero(ddev->cap_mask);
+ dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
+ dma_cap_set(DMA_SLAVE, ddev->cap_mask);
+ ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
+ ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
+ ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
+ BIT(DMA_MEM_TO_MEM);
+ ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ ddev->max_burst = XDMAC_MAX_WORDS;
+ ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
+ ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
+ ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
+ ddev->device_config = uniphier_xdmac_slave_config;
+ ddev->device_terminate_all = uniphier_xdmac_terminate_all;
+ ddev->device_synchronize = uniphier_xdmac_synchronize;
+ ddev->device_tx_status = dma_cookie_status;
+ ddev->device_issue_pending = uniphier_xdmac_issue_pending;
+ INIT_LIST_HEAD(&ddev->channels);
+
+ for (i = 0; i < nr_chans; i++) {
+ ret = uniphier_xdmac_chan_init(xdev, i);
+ if (ret) {
+ dev_err(dev,
+ "Failed to initialize XDMAC channel %d\n", i);
+ return ret;
+ }
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "Failed to get IRQ\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, uniphier_xdmac_irq_handler,
+ IRQF_SHARED, "xdmac", xdev);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ\n");
+ return ret;
+ }
+
+ ret = dma_async_device_register(ddev);
+ if (ret) {
+ dev_err(dev, "Failed to register XDMA device\n");
+ return ret;
+ }
+
+ ret = of_dma_controller_register(dev->of_node,
+ of_dma_uniphier_xlate, xdev);
+ if (ret) {
+ dev_err(dev, "Failed to register XDMA controller\n");
+ goto out_unregister_dmac;
+ }
+
+ platform_set_drvdata(pdev, xdev);
+
+ dev_info(&pdev->dev, "UniPhier XDMAC driver (%d channels)\n",
+ nr_chans);
+
+ return 0;
+
+out_unregister_dmac:
+ dma_async_device_unregister(ddev);
+
+ return ret;
+}
+
+static int uniphier_xdmac_remove(struct platform_device *pdev)
+{
+ struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
+ struct dma_device *ddev = &xdev->ddev;
+ struct dma_chan *chan;
+ int ret;
+
+ /*
+ * Before reaching here, almost all descriptors have been freed by the
+ * ->device_free_chan_resources() hook. However, each channel might
+ * be still holding one descriptor that was on-flight at that moment.
+ * Terminate it to make sure this hardware is no longer running. Then,
+ * free the channel resources once again to avoid memory leak.
+ */
+ list_for_each_entry(chan, &ddev->channels, device_node) {
+ ret = dmaengine_terminate_sync(chan);
+ if (ret)
+ return ret;
+ uniphier_xdmac_free_chan_resources(chan);
+ }
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(ddev);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_xdmac_match[] = {
+ { .compatible = "socionext,uniphier-xdmac" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_xdmac_match);
+
+static struct platform_driver uniphier_xdmac_driver = {
+ .probe = uniphier_xdmac_probe,
+ .remove = uniphier_xdmac_remove,
+ .driver = {
+ .name = "uniphier-xdmac",
+ .of_match_table = uniphier_xdmac_match,
+ },
+};
+module_platform_driver(uniphier_xdmac_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_DESCRIPTION("UniPhier external DMA controller driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
2019-12-18 0:57 ` Kunihiko Hayashi
@ 2019-12-27 6:34 ` Vinod Koul
-1 siblings, 0 replies; 16+ messages in thread
From: Vinod Koul @ 2019-12-27 6:34 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland,
dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar
On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> This adds external DMA controller driver implemented in Socionext
> UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
>
> Since this driver does not support the the way to transfer size
> unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
You mean driver does not support any unaligned bursts?
> +static int uniphier_xdmac_probe(struct platform_device *pdev)
> +{
> + struct uniphier_xdmac_device *xdev;
> + struct device *dev = &pdev->dev;
> + struct dma_device *ddev;
> + int irq;
> + int nr_chans;
> + int i, ret;
> +
> + if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
> + return -EINVAL;
> + if (nr_chans > XDMAC_MAX_CHANS)
> + nr_chans = XDMAC_MAX_CHANS;
> +
> + xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
> + GFP_KERNEL);
> + if (!xdev)
> + return -ENOMEM;
> +
> + xdev->nr_chans = nr_chans;
> + xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(xdev->reg_base))
> + return PTR_ERR(xdev->reg_base);
> +
> + ddev = &xdev->ddev;
> + ddev->dev = dev;
> + dma_cap_zero(ddev->cap_mask);
> + dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
> + dma_cap_set(DMA_SLAVE, ddev->cap_mask);
> + ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> + ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
> + BIT(DMA_MEM_TO_MEM);
> + ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> + ddev->max_burst = XDMAC_MAX_WORDS;
> + ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
> + ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
> + ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
> + ddev->device_config = uniphier_xdmac_slave_config;
> + ddev->device_terminate_all = uniphier_xdmac_terminate_all;
> + ddev->device_synchronize = uniphier_xdmac_synchronize;
> + ddev->device_tx_status = dma_cookie_status;
> + ddev->device_issue_pending = uniphier_xdmac_issue_pending;
> + INIT_LIST_HEAD(&ddev->channels);
> +
> + for (i = 0; i < nr_chans; i++) {
> + ret = uniphier_xdmac_chan_init(xdev, i);
> + if (ret) {
> + dev_err(dev,
> + "Failed to initialize XDMAC channel %d\n", i);
> + return ret;
so on error for channel N we leave N-1 channels initialized?
> +static int uniphier_xdmac_remove(struct platform_device *pdev)
> +{
> + struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
> + struct dma_device *ddev = &xdev->ddev;
> + struct dma_chan *chan;
> + int ret;
> +
> + /*
> + * Before reaching here, almost all descriptors have been freed by the
> + * ->device_free_chan_resources() hook. However, each channel might
> + * be still holding one descriptor that was on-flight at that moment.
> + * Terminate it to make sure this hardware is no longer running. Then,
> + * free the channel resources once again to avoid memory leak.
> + */
> + list_for_each_entry(chan, &ddev->channels, device_node) {
> + ret = dmaengine_terminate_sync(chan);
> + if (ret)
> + return ret;
> + uniphier_xdmac_free_chan_resources(chan);
terminating sounds okayish but not freeing here. .ree_chan_resources()
should have been called already and that should ensure that termination
is already done...
--
~Vinod
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
@ 2019-12-27 6:34 ` Vinod Koul
0 siblings, 0 replies; 16+ messages in thread
From: Vinod Koul @ 2019-12-27 6:34 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Mark Rutland, devicetree, Masami Hiramatsu, Jassi Brar,
linux-kernel, Masahiro Yamada, Rob Herring, dmaengine,
Dan Williams, linux-arm-kernel
On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> This adds external DMA controller driver implemented in Socionext
> UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
>
> Since this driver does not support the the way to transfer size
> unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
You mean driver does not support any unaligned bursts?
> +static int uniphier_xdmac_probe(struct platform_device *pdev)
> +{
> + struct uniphier_xdmac_device *xdev;
> + struct device *dev = &pdev->dev;
> + struct dma_device *ddev;
> + int irq;
> + int nr_chans;
> + int i, ret;
> +
> + if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
> + return -EINVAL;
> + if (nr_chans > XDMAC_MAX_CHANS)
> + nr_chans = XDMAC_MAX_CHANS;
> +
> + xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
> + GFP_KERNEL);
> + if (!xdev)
> + return -ENOMEM;
> +
> + xdev->nr_chans = nr_chans;
> + xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(xdev->reg_base))
> + return PTR_ERR(xdev->reg_base);
> +
> + ddev = &xdev->ddev;
> + ddev->dev = dev;
> + dma_cap_zero(ddev->cap_mask);
> + dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
> + dma_cap_set(DMA_SLAVE, ddev->cap_mask);
> + ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> + ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
> + BIT(DMA_MEM_TO_MEM);
> + ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> + ddev->max_burst = XDMAC_MAX_WORDS;
> + ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
> + ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
> + ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
> + ddev->device_config = uniphier_xdmac_slave_config;
> + ddev->device_terminate_all = uniphier_xdmac_terminate_all;
> + ddev->device_synchronize = uniphier_xdmac_synchronize;
> + ddev->device_tx_status = dma_cookie_status;
> + ddev->device_issue_pending = uniphier_xdmac_issue_pending;
> + INIT_LIST_HEAD(&ddev->channels);
> +
> + for (i = 0; i < nr_chans; i++) {
> + ret = uniphier_xdmac_chan_init(xdev, i);
> + if (ret) {
> + dev_err(dev,
> + "Failed to initialize XDMAC channel %d\n", i);
> + return ret;
so on error for channel N we leave N-1 channels initialized?
> +static int uniphier_xdmac_remove(struct platform_device *pdev)
> +{
> + struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
> + struct dma_device *ddev = &xdev->ddev;
> + struct dma_chan *chan;
> + int ret;
> +
> + /*
> + * Before reaching here, almost all descriptors have been freed by the
> + * ->device_free_chan_resources() hook. However, each channel might
> + * be still holding one descriptor that was on-flight at that moment.
> + * Terminate it to make sure this hardware is no longer running. Then,
> + * free the channel resources once again to avoid memory leak.
> + */
> + list_for_each_entry(chan, &ddev->channels, device_node) {
> + ret = dmaengine_terminate_sync(chan);
> + if (ret)
> + return ret;
> + uniphier_xdmac_free_chan_resources(chan);
terminating sounds okayish but not freeing here. .ree_chan_resources()
should have been called already and that should ensure that termination
is already done...
--
~Vinod
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
2019-12-18 0:56 ` Kunihiko Hayashi
@ 2020-01-08 3:55 ` Rob Herring
-1 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2020-01-08 3:55 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Vinod Koul, Dan Williams, Masahiro Yamada, Mark Rutland,
dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar
On Wed, Dec 18, 2019 at 09:56:59AM +0900, Kunihiko Hayashi wrote:
> Add external DMA controller bindings implemented in Socionext UniPhier
> SoCs.
>
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> ---
> .../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
> 1 file changed, 86 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
Please make this a DT schema. See
Documentation/devicetree/writing-schema.rst.
>
> diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> new file mode 100644
> index 00000000..4e3927f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> @@ -0,0 +1,86 @@
> +Socionext UniPhier external DMA controller bindings
> +
> +This describes the devicetree bindings for an external DMA engine to perform
> +memory-to-memory or peripheral-to-memory data transfer, implemented in
> +Socionext UniPhier SoCs.
> +
> +* DMA controller
> +
> +Required properties:
> +- compatible: Should be "socionext,uniphier-xdmac".
> +- reg: Specifies offset and length of the register set for the device.
> +- interrupts: An interrupt specifier associated with the DMA controller.
> +- #dma-cells: Must be <2>. The first cell represents the channel index.
> + The second cell represents the factor for transfer request.
> + This is mentioned in DMA client section.
> +- dma-channels : Number of DMA channels supported. Should be 16.
If always 16, then why do you need this?
> +
> +Example:
> + xdmac: dma-controller@5fc10000 {
> + compatible = "socionext,uniphier-xdmac";
> + reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
> + interrupts = <0 188 4>;
> + #dma-cells = <2>;
> + dma-channels = <16>;
> + };
> +
> +* DMA client
> +
> +Required properties:
> +- dmas: A list of DMA channel requests.
> +- dma-names: Names of the requested channels corresponding to dmas.
> +
> +DMA clients must use the format described in the dma.txt file, using a two cell
> +specifier for each channel.
No need to redefine the client binding here. Just need the cell format
as below.
> +
> +Each DMA request consists of 3 cells:
> + 1. A phandle pointing to the DMA controller
> + 2. Channel index
> + 3. Transfer request factor number, If no transfer factor, use 0.
> + The number is SoC-specific, and this should be specified with relation
> + to the device to use the DMA controller. The list of the factor number
> + can be found below.
> +
> + 0x0 none
> + 0x8 UART ch0 Rx
> + 0x9 UART ch0 Tx
> + 0xa UART ch1 Rx
> + 0xb UART ch1 Tx
> + 0xc UART ch2 Rx
> + 0xd UART ch2 Tx
> + 0xe UART ch3 Rx
> + 0xf UART ch3 Tx
> + 0x14 SCSSI ch1 Rx
> + 0x15 SCSSI ch1 Tx
> + 0x16 SCSSI ch0 Rx
> + 0x17 SCSSI ch0 Tx
> + 0x18 SCSSI ch2 Rx
> + 0x19 SCSSI ch2 Tx
> + 0x1a SCSSI ch3 Rx
> + 0x1b SCSSI ch3 Tx
> + 0x21 I2C ch0 Rx
> + 0x22 I2C ch0 Tx
> + 0x23 I2C ch1 Rx
> + 0x24 I2C ch1 Tx
> + 0x25 I2C ch2 Rx
> + 0x26 I2C ch2 Tx
> + 0x27 I2C ch3 Rx
> + 0x28 I2C ch3 Tx
> + 0x29 I2C ch4 Rx
> + 0x2a I2C ch4 Tx
> + 0x2b I2C ch5 Rx
> + 0x2c I2C ch5 Tx
> + 0x2d I2C ch6 Rx
> + 0x2e I2C ch6 Tx
> +
> +Example:
> + spi3: spi@54006300 {
> + compatible = "socionext,uniphier-scssi";
> + reg = <0x54006300 0x100>;
> + interrupts = <0 39 4>;
> + clocks = <&peri_clk 14>;
> + resets = <&peri_rst 14>;
> +
> + dmas = <&xdmac 0 0x1a>, <&xdmac 1 0x1b>;
> + dma-names = "rx", "tx";
> + };
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
@ 2020-01-08 3:55 ` Rob Herring
0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2020-01-08 3:55 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Mark Rutland, devicetree, Masami Hiramatsu, Jassi Brar,
linux-kernel, Masahiro Yamada, Vinod Koul, dmaengine,
Dan Williams, linux-arm-kernel
On Wed, Dec 18, 2019 at 09:56:59AM +0900, Kunihiko Hayashi wrote:
> Add external DMA controller bindings implemented in Socionext UniPhier
> SoCs.
>
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> ---
> .../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
> 1 file changed, 86 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
Please make this a DT schema. See
Documentation/devicetree/writing-schema.rst.
>
> diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> new file mode 100644
> index 00000000..4e3927f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> @@ -0,0 +1,86 @@
> +Socionext UniPhier external DMA controller bindings
> +
> +This describes the devicetree bindings for an external DMA engine to perform
> +memory-to-memory or peripheral-to-memory data transfer, implemented in
> +Socionext UniPhier SoCs.
> +
> +* DMA controller
> +
> +Required properties:
> +- compatible: Should be "socionext,uniphier-xdmac".
> +- reg: Specifies offset and length of the register set for the device.
> +- interrupts: An interrupt specifier associated with the DMA controller.
> +- #dma-cells: Must be <2>. The first cell represents the channel index.
> + The second cell represents the factor for transfer request.
> + This is mentioned in DMA client section.
> +- dma-channels : Number of DMA channels supported. Should be 16.
If always 16, then why do you need this?
> +
> +Example:
> + xdmac: dma-controller@5fc10000 {
> + compatible = "socionext,uniphier-xdmac";
> + reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
> + interrupts = <0 188 4>;
> + #dma-cells = <2>;
> + dma-channels = <16>;
> + };
> +
> +* DMA client
> +
> +Required properties:
> +- dmas: A list of DMA channel requests.
> +- dma-names: Names of the requested channels corresponding to dmas.
> +
> +DMA clients must use the format described in the dma.txt file, using a two cell
> +specifier for each channel.
No need to redefine the client binding here. Just need the cell format
as below.
> +
> +Each DMA request consists of 3 cells:
> + 1. A phandle pointing to the DMA controller
> + 2. Channel index
> + 3. Transfer request factor number, If no transfer factor, use 0.
> + The number is SoC-specific, and this should be specified with relation
> + to the device to use the DMA controller. The list of the factor number
> + can be found below.
> +
> + 0x0 none
> + 0x8 UART ch0 Rx
> + 0x9 UART ch0 Tx
> + 0xa UART ch1 Rx
> + 0xb UART ch1 Tx
> + 0xc UART ch2 Rx
> + 0xd UART ch2 Tx
> + 0xe UART ch3 Rx
> + 0xf UART ch3 Tx
> + 0x14 SCSSI ch1 Rx
> + 0x15 SCSSI ch1 Tx
> + 0x16 SCSSI ch0 Rx
> + 0x17 SCSSI ch0 Tx
> + 0x18 SCSSI ch2 Rx
> + 0x19 SCSSI ch2 Tx
> + 0x1a SCSSI ch3 Rx
> + 0x1b SCSSI ch3 Tx
> + 0x21 I2C ch0 Rx
> + 0x22 I2C ch0 Tx
> + 0x23 I2C ch1 Rx
> + 0x24 I2C ch1 Tx
> + 0x25 I2C ch2 Rx
> + 0x26 I2C ch2 Tx
> + 0x27 I2C ch3 Rx
> + 0x28 I2C ch3 Tx
> + 0x29 I2C ch4 Rx
> + 0x2a I2C ch4 Tx
> + 0x2b I2C ch5 Rx
> + 0x2c I2C ch5 Tx
> + 0x2d I2C ch6 Rx
> + 0x2e I2C ch6 Tx
> +
> +Example:
> + spi3: spi@54006300 {
> + compatible = "socionext,uniphier-scssi";
> + reg = <0x54006300 0x100>;
> + interrupts = <0 39 4>;
> + clocks = <&peri_clk 14>;
> + resets = <&peri_rst 14>;
> +
> + dmas = <&xdmac 0 0x1a>, <&xdmac 1 0x1b>;
> + dma-names = "rx", "tx";
> + };
> --
> 2.7.4
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
2019-12-27 6:34 ` Vinod Koul
@ 2020-01-09 12:12 ` Kunihiko Hayashi
-1 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2020-01-09 12:12 UTC (permalink / raw)
To: Vinod Koul
Cc: Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland,
dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar
Hi Vinod,
Thank you for your comment.
On Fri, 27 Dec 2019 12:04:11 +0530 <vkoul@kernel.org> wrote:
> On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> > This adds external DMA controller driver implemented in Socionext
> > UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
> >
> > Since this driver does not support the the way to transfer size
> > unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
>
> You mean driver does not support any unaligned bursts?
Yes. If transfer size is unaligned to burst size, the final transfer
will be overrun.
>
> > +static int uniphier_xdmac_probe(struct platform_device *pdev)
> > +{
> > + struct uniphier_xdmac_device *xdev;
> > + struct device *dev = &pdev->dev;
> > + struct dma_device *ddev;
> > + int irq;
> > + int nr_chans;
> > + int i, ret;
> > +
> > + if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
> > + return -EINVAL;
> > + if (nr_chans > XDMAC_MAX_CHANS)
> > + nr_chans = XDMAC_MAX_CHANS;
> > +
> > + xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
> > + GFP_KERNEL);
> > + if (!xdev)
> > + return -ENOMEM;
> > +
> > + xdev->nr_chans = nr_chans;
> > + xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(xdev->reg_base))
> > + return PTR_ERR(xdev->reg_base);
> > +
> > + ddev = &xdev->ddev;
> > + ddev->dev = dev;
> > + dma_cap_zero(ddev->cap_mask);
> > + dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
> > + dma_cap_set(DMA_SLAVE, ddev->cap_mask);
> > + ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> > + ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> > + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
> > + BIT(DMA_MEM_TO_MEM);
> > + ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> > + ddev->max_burst = XDMAC_MAX_WORDS;
> > + ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
> > + ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
> > + ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
> > + ddev->device_config = uniphier_xdmac_slave_config;
> > + ddev->device_terminate_all = uniphier_xdmac_terminate_all;
> > + ddev->device_synchronize = uniphier_xdmac_synchronize;
> > + ddev->device_tx_status = dma_cookie_status;
> > + ddev->device_issue_pending = uniphier_xdmac_issue_pending;
> > + INIT_LIST_HEAD(&ddev->channels);
> > +
> > + for (i = 0; i < nr_chans; i++) {
> > + ret = uniphier_xdmac_chan_init(xdev, i);
> > + if (ret) {
> > + dev_err(dev,
> > + "Failed to initialize XDMAC channel %d\n", i);
> > + return ret;
>
> so on error for channel N we leave N-1 channels initialized?
The uniphier_xdmac_chan_init() always returns 0, so this error decision
can be removed.
> > +static int uniphier_xdmac_remove(struct platform_device *pdev)
> > +{
> > + struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
> > + struct dma_device *ddev = &xdev->ddev;
> > + struct dma_chan *chan;
> > + int ret;
> > +
> > + /*
> > + * Before reaching here, almost all descriptors have been freed by the
> > + * ->device_free_chan_resources() hook. However, each channel might
> > + * be still holding one descriptor that was on-flight at that moment.
> > + * Terminate it to make sure this hardware is no longer running. Then,
> > + * free the channel resources once again to avoid memory leak.
> > + */
> > + list_for_each_entry(chan, &ddev->channels, device_node) {
> > + ret = dmaengine_terminate_sync(chan);
> > + if (ret)
> > + return ret;
> > + uniphier_xdmac_free_chan_resources(chan);
>
> terminating sounds okayish but not freeing here. .ree_chan_resources()
> should have been called already and that should ensure that termination
> is already done...
If all transfers are complete, .device_free_chan_resources() should be called.
Since _remove() might be called asynchronously, this is post-processing just
before transfer completion.
Thank you,
---
Best Regards,
Kunihiko Hayashi
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
@ 2020-01-09 12:12 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2020-01-09 12:12 UTC (permalink / raw)
To: Vinod Koul
Cc: Mark Rutland, devicetree, Masami Hiramatsu, Jassi Brar,
linux-kernel, Masahiro Yamada, Rob Herring, dmaengine,
Dan Williams, linux-arm-kernel
Hi Vinod,
Thank you for your comment.
On Fri, 27 Dec 2019 12:04:11 +0530 <vkoul@kernel.org> wrote:
> On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> > This adds external DMA controller driver implemented in Socionext
> > UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
> >
> > Since this driver does not support the the way to transfer size
> > unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
>
> You mean driver does not support any unaligned bursts?
Yes. If transfer size is unaligned to burst size, the final transfer
will be overrun.
>
> > +static int uniphier_xdmac_probe(struct platform_device *pdev)
> > +{
> > + struct uniphier_xdmac_device *xdev;
> > + struct device *dev = &pdev->dev;
> > + struct dma_device *ddev;
> > + int irq;
> > + int nr_chans;
> > + int i, ret;
> > +
> > + if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans))
> > + return -EINVAL;
> > + if (nr_chans > XDMAC_MAX_CHANS)
> > + nr_chans = XDMAC_MAX_CHANS;
> > +
> > + xdev = devm_kzalloc(dev, struct_size(xdev, channels, nr_chans),
> > + GFP_KERNEL);
> > + if (!xdev)
> > + return -ENOMEM;
> > +
> > + xdev->nr_chans = nr_chans;
> > + xdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(xdev->reg_base))
> > + return PTR_ERR(xdev->reg_base);
> > +
> > + ddev = &xdev->ddev;
> > + ddev->dev = dev;
> > + dma_cap_zero(ddev->cap_mask);
> > + dma_cap_set(DMA_MEMCPY, ddev->cap_mask);
> > + dma_cap_set(DMA_SLAVE, ddev->cap_mask);
> > + ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> > + ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS;
> > + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
> > + BIT(DMA_MEM_TO_MEM);
> > + ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
> > + ddev->max_burst = XDMAC_MAX_WORDS;
> > + ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources;
> > + ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy;
> > + ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg;
> > + ddev->device_config = uniphier_xdmac_slave_config;
> > + ddev->device_terminate_all = uniphier_xdmac_terminate_all;
> > + ddev->device_synchronize = uniphier_xdmac_synchronize;
> > + ddev->device_tx_status = dma_cookie_status;
> > + ddev->device_issue_pending = uniphier_xdmac_issue_pending;
> > + INIT_LIST_HEAD(&ddev->channels);
> > +
> > + for (i = 0; i < nr_chans; i++) {
> > + ret = uniphier_xdmac_chan_init(xdev, i);
> > + if (ret) {
> > + dev_err(dev,
> > + "Failed to initialize XDMAC channel %d\n", i);
> > + return ret;
>
> so on error for channel N we leave N-1 channels initialized?
The uniphier_xdmac_chan_init() always returns 0, so this error decision
can be removed.
> > +static int uniphier_xdmac_remove(struct platform_device *pdev)
> > +{
> > + struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev);
> > + struct dma_device *ddev = &xdev->ddev;
> > + struct dma_chan *chan;
> > + int ret;
> > +
> > + /*
> > + * Before reaching here, almost all descriptors have been freed by the
> > + * ->device_free_chan_resources() hook. However, each channel might
> > + * be still holding one descriptor that was on-flight at that moment.
> > + * Terminate it to make sure this hardware is no longer running. Then,
> > + * free the channel resources once again to avoid memory leak.
> > + */
> > + list_for_each_entry(chan, &ddev->channels, device_node) {
> > + ret = dmaengine_terminate_sync(chan);
> > + if (ret)
> > + return ret;
> > + uniphier_xdmac_free_chan_resources(chan);
>
> terminating sounds okayish but not freeing here. .ree_chan_resources()
> should have been called already and that should ensure that termination
> is already done...
If all transfers are complete, .device_free_chan_resources() should be called.
Since _remove() might be called asynchronously, this is post-processing just
before transfer completion.
Thank you,
---
Best Regards,
Kunihiko Hayashi
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
2020-01-08 3:55 ` Rob Herring
@ 2020-01-09 12:20 ` Kunihiko Hayashi
-1 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2020-01-09 12:20 UTC (permalink / raw)
To: Rob Herring
Cc: Vinod Koul, Dan Williams, Masahiro Yamada, Mark Rutland,
dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar
Hi Rob,
Thank you for your comment.
On Tue, 7 Jan 2020 21:55:37 -0600 <robh@kernel.org> wrote:
> On Wed, Dec 18, 2019 at 09:56:59AM +0900, Kunihiko Hayashi wrote:
> > Add external DMA controller bindings implemented in Socionext UniPhier
> > SoCs.
> >
> > Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> > ---
> > .../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
> > 1 file changed, 86 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
>
> Please make this a DT schema. See
> Documentation/devicetree/writing-schema.rst.
Although I'm not familiar with this format, I'll try to make it.
> >
> > diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> > new file mode 100644
> > index 00000000..4e3927f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> > @@ -0,0 +1,86 @@
> > +Socionext UniPhier external DMA controller bindings
> > +
> > +This describes the devicetree bindings for an external DMA engine to perform
> > +memory-to-memory or peripheral-to-memory data transfer, implemented in
> > +Socionext UniPhier SoCs.
> > +
> > +* DMA controller
> > +
> > +Required properties:
> > +- compatible: Should be "socionext,uniphier-xdmac".
> > +- reg: Specifies offset and length of the register set for the device.
> > +- interrupts: An interrupt specifier associated with the DMA controller.
> > +- #dma-cells: Must be <2>. The first cell represents the channel index.
> > + The second cell represents the factor for transfer request.
> > + This is mentioned in DMA client section.
> > +- dma-channels : Number of DMA channels supported. Should be 16.
>
> If always 16, then why do you need this?
Oh, currently this means 16 or less, though, this is the number supported
by the controller. I'll fix it.
>
> > +
> > +Example:
> > + xdmac: dma-controller@5fc10000 {
> > + compatible = "socionext,uniphier-xdmac";
> > + reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
> > + interrupts = <0 188 4>;
> > + #dma-cells = <2>;
> > + dma-channels = <16>;
> > + };
> > +
> > +* DMA client
> > +
> > +Required properties:
> > +- dmas: A list of DMA channel requests.
> > +- dma-names: Names of the requested channels corresponding to dmas.
> > +
> > +DMA clients must use the format described in the dma.txt file, using a two cell
> > +specifier for each channel.
>
> No need to redefine the client binding here. Just need the cell format
> as below.
I see. I'll replace with the cell format.
Thank you,
---
Best Regards,
Kunihiko Hayashi
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings
@ 2020-01-09 12:20 ` Kunihiko Hayashi
0 siblings, 0 replies; 16+ messages in thread
From: Kunihiko Hayashi @ 2020-01-09 12:20 UTC (permalink / raw)
To: Rob Herring
Cc: Mark Rutland, devicetree, Masami Hiramatsu, Jassi Brar,
linux-kernel, Masahiro Yamada, Vinod Koul, dmaengine,
Dan Williams, linux-arm-kernel
Hi Rob,
Thank you for your comment.
On Tue, 7 Jan 2020 21:55:37 -0600 <robh@kernel.org> wrote:
> On Wed, Dec 18, 2019 at 09:56:59AM +0900, Kunihiko Hayashi wrote:
> > Add external DMA controller bindings implemented in Socionext UniPhier
> > SoCs.
> >
> > Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> > ---
> > .../devicetree/bindings/dma/uniphier-xdmac.txt | 86 ++++++++++++++++++++++
> > 1 file changed, 86 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
>
> Please make this a DT schema. See
> Documentation/devicetree/writing-schema.rst.
Although I'm not familiar with this format, I'll try to make it.
> >
> > diff --git a/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> > new file mode 100644
> > index 00000000..4e3927f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/uniphier-xdmac.txt
> > @@ -0,0 +1,86 @@
> > +Socionext UniPhier external DMA controller bindings
> > +
> > +This describes the devicetree bindings for an external DMA engine to perform
> > +memory-to-memory or peripheral-to-memory data transfer, implemented in
> > +Socionext UniPhier SoCs.
> > +
> > +* DMA controller
> > +
> > +Required properties:
> > +- compatible: Should be "socionext,uniphier-xdmac".
> > +- reg: Specifies offset and length of the register set for the device.
> > +- interrupts: An interrupt specifier associated with the DMA controller.
> > +- #dma-cells: Must be <2>. The first cell represents the channel index.
> > + The second cell represents the factor for transfer request.
> > + This is mentioned in DMA client section.
> > +- dma-channels : Number of DMA channels supported. Should be 16.
>
> If always 16, then why do you need this?
Oh, currently this means 16 or less, though, this is the number supported
by the controller. I'll fix it.
>
> > +
> > +Example:
> > + xdmac: dma-controller@5fc10000 {
> > + compatible = "socionext,uniphier-xdmac";
> > + reg = <0x5fc10000 0x1000>, <0x5fc20000 0x800>;
> > + interrupts = <0 188 4>;
> > + #dma-cells = <2>;
> > + dma-channels = <16>;
> > + };
> > +
> > +* DMA client
> > +
> > +Required properties:
> > +- dmas: A list of DMA channel requests.
> > +- dma-names: Names of the requested channels corresponding to dmas.
> > +
> > +DMA clients must use the format described in the dma.txt file, using a two cell
> > +specifier for each channel.
>
> No need to redefine the client binding here. Just need the cell format
> as below.
I see. I'll replace with the cell format.
Thank you,
---
Best Regards,
Kunihiko Hayashi
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
2020-01-09 12:12 ` Kunihiko Hayashi
@ 2020-01-10 8:01 ` Vinod Koul
-1 siblings, 0 replies; 16+ messages in thread
From: Vinod Koul @ 2020-01-10 8:01 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Dan Williams, Masahiro Yamada, Rob Herring, Mark Rutland,
dmaengine, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar
On 09-01-20, 21:12, Kunihiko Hayashi wrote:
> Hi Vinod,
>
> Thank you for your comment.
>
> On Fri, 27 Dec 2019 12:04:11 +0530 <vkoul@kernel.org> wrote:
>
> > On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> > > This adds external DMA controller driver implemented in Socionext
> > > UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
> > >
> > > Since this driver does not support the the way to transfer size
> > > unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
> >
> > You mean driver does not support any unaligned bursts?
>
> Yes. If transfer size is unaligned to burst size, the final transfer
> will be overrun.
That is fine, you shoudl return error for bursts which are not aligned
when preparing the descriptors
--
~Vinod
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver
@ 2020-01-10 8:01 ` Vinod Koul
0 siblings, 0 replies; 16+ messages in thread
From: Vinod Koul @ 2020-01-10 8:01 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Mark Rutland, devicetree, Masami Hiramatsu, Jassi Brar,
linux-kernel, Masahiro Yamada, Rob Herring, dmaengine,
Dan Williams, linux-arm-kernel
On 09-01-20, 21:12, Kunihiko Hayashi wrote:
> Hi Vinod,
>
> Thank you for your comment.
>
> On Fri, 27 Dec 2019 12:04:11 +0530 <vkoul@kernel.org> wrote:
>
> > On 18-12-19, 09:57, Kunihiko Hayashi wrote:
> > > This adds external DMA controller driver implemented in Socionext
> > > UniPhier SoCs. This driver supports DMA_MEMCPY and DMA_SLAVE modes.
> > >
> > > Since this driver does not support the the way to transfer size
> > > unaligned to burst width, 'src_maxburst' or 'dst_maxburst' of
> >
> > You mean driver does not support any unaligned bursts?
>
> Yes. If transfer size is unaligned to burst size, the final transfer
> will be overrun.
That is fine, you shoudl return error for bursts which are not aligned
when preparing the descriptors
--
~Vinod
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2020-01-10 8:02 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-18 0:56 [PATCH 0/2] dmaengine: Add UniPhier XDMAC driver Kunihiko Hayashi
2019-12-18 0:56 ` Kunihiko Hayashi
2019-12-18 0:56 ` [PATCH 1/2] dt-bindings: dmaengine: Add UniPhier external DMA controller bindings Kunihiko Hayashi
2019-12-18 0:56 ` Kunihiko Hayashi
2020-01-08 3:55 ` Rob Herring
2020-01-08 3:55 ` Rob Herring
2020-01-09 12:20 ` Kunihiko Hayashi
2020-01-09 12:20 ` Kunihiko Hayashi
2019-12-18 0:57 ` [PATCH 2/2] dmaengine: uniphier-xdmac: Add UniPhier external DMA controller driver Kunihiko Hayashi
2019-12-18 0:57 ` Kunihiko Hayashi
2019-12-27 6:34 ` Vinod Koul
2019-12-27 6:34 ` Vinod Koul
2020-01-09 12:12 ` Kunihiko Hayashi
2020-01-09 12:12 ` Kunihiko Hayashi
2020-01-10 8:01 ` Vinod Koul
2020-01-10 8:01 ` Vinod Koul
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.