Skip to contentSkip to conversation

ARM: s3c64xx: Let amba-pl08x driver handle DMA

PATCH In review Tomasz Figa 5 participants 45 messages Aug 11, 2013 – Sep 2, 2013

Subsystems (10)
lore
Share & tools
lore
#0 lore raw

cover ARM: s3c64xx: Let amba-pl08x driver handle DMA

This is first non-RFC version of my patches extending support of amba-pl08x DMA engine driver to PL080S DMA engine (PL080 modified by Samsung) found in Samsung S3C64xx SoCs.

Due to changes scattered across different areas of kernel, patches are based on merged 3 branches:
- for-next of Kgene's Samsung tree,
- clk-next of Mike's clock tree,
- next of Vinod's slave DMA tree.

To ease testing I have prepared a branch in my private tree for anyone willing to check the patches out:

	git://github.com/tom3q/linux.git v3.12-pl080

Dependencies (already applied in my branch):
- for patches 14 and 16 - CCF-based clock driver for s3c64xx.

Some of the patches not related to the amba-pl08x driver itself can be likely applied into appropriate trees separately, namely:
- 09/18 - ASoC: Samsung: Do not queue cyclic buffers multiple times,
- 14/18 - clk: samsung: s3c64xx: Add aliases for DMA clocks.

After patch 14/18, both old and new DMA drivers can be supported on S3C64xx, depending on Kconfig options. Patches 15-18 remove the old driver leaving support only for the generic pl08x driver. Feel free to drop those patches for now if we want more testing, but I don't suspect any problems.

On S3C64xx-based Mini6410 and SMDK6410 boards, with I2S audio playback and capture (including full duplex operation) and also SPI using spidev:

Changes since RFC v2:
- Added clkdev lookups to old clock driver.
- Added patches removing the old DMA driver and any remaining code needed by it.
- Fixed DMA support for SPI.
- Added a word about PL080S to amba-pl08x.c file header.
- Changed definition of LLI words from enums to macros.
- Extended debugging messages to handle PL080S variant as well.
- Little cleanup of LLI dumping code.
- Added check for peripheral flow control, which is unsupported by PL080S to dma_set_runtime_config.
- Corrected transfer size mask of PL080S.

Changes since RFC v1:
- Returned to original way of storing quirks as booleans, as suggested by Russell, Linus and Arnd.
- Added reg_config field to pl08x_phy_chan struct, which stores variant-specific address of channel config register, as suggested by Russell.
- Simplified handling of extended maximum transfer size of PL080S (no more conditional passing of 0 as length to pl08x_cctl_bits()).
- Reworked LLI handling in the driver to stop casting arbitrary memory to a struct and allow different word count of LLI entry, as suggested by Linus.
- Removed AMBA ID override from S3C64xx PL080 initialization code.
- Fixed brokenness of Samsung DMA wrapper API, which caused cyclic buffers to be queued multiple times when DMA engine is used.
- Included patch adding clock aliases for DMA engines (depends on Common Clock Framework driver for S3C64xx).
- Fixed several minor stylistic issues.

For reference, here is the original description of the series:

One of the biggest roadblocks on the way of S3C64xx to DeviceTree support is its DMA driver, which is completely platform-specific and provides private API (s3c-dma), not even saying that its design is completely against multiplatform-awareness.

The DMA controller present on this SoC series is a custom variant of ARM PrimeCell PL080 modified by Samsung to add some extra features. It is mostly compatible with original PL080, except:
- CH_CONTROL2 register is added between CH_CONTROL and CH_CONFIG,
- offset of CH_CONFIG register is different,
- transfer size field is moved from CH_CONTROL to CH_CONTROL2,
- transfer size field is extended to 24 bits, allowing much bigger single transfer,
- LLI consists of one more word, to account for CH_CONTROL2 register.

Since all the rest is fully compatible with standard PL080 there is no point in having separate driver just for this single variant, so I decided to look into adding support for it to the amba-pl08x driver.

There was already some attempt to achieve this before, but this was before Russel's big rework of the driver to use virtual channels, making the old patches being not much of use.

This RFC series is a proof of concept that I managed to make during last days of hacking. Except one patch adding clkdev lookup to clock driver (which is being replaced with a CCF-compliant driver ATM), this is enough to get memcpy and slave transfers to work on S3C64xx.

I have tested this on Mini6410 and SMDK6410 boards using dmatest for memcpy and Samsung I2S with madplay/aplay for slave transfers. Unfortunately I do not have access to other platforms with PL08x so I could not test for any regressions introduced on them.

Credits for two patches go to Alban Bedel, who made a series fixing this driver to make it usable with audio drivers. I rebased his patches on top of mine and corrected coding style a bit.

OK, that's all. Any comments are welcome. Feel free to start throwing eggs and tomatoes if you find this awful, but I won't be upset if I get some Tested-by or Acked-by as well. ;)

Alban Bedel (2):
dmaengine: PL08x: Fix reading the byte count in cctl
dmaengine: PL08x: Add cyclic transfer support

Tomasz Figa (16):
dmaengine: PL08x: Refactor pl08x_getbytes_chan() to lower indentation
dmaengine: PL08x: Add support for different offset of CONFIG register
dmaengine: PL08x: Rework LLI handling to be less fragile
dmaengine: PL08x: Move LLI dumping code into separate function
dmaengine: PL08x: Add support for PL080S variant
dmaengine: PL08x: Add support for different maximum transfer size
ASoC: Samsung: Do not queue cyclic buffers multiple times
spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX
ASoC: Samsung: Do not require legacy DMA API in case of S3C64XX
ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver
ARM: s3c64xx: clock: Add clkdev lookup for DMA clocks
clk: samsung: s3c64xx: Add aliases for DMA clocks
ARM: s3c64xx: Remove legacy DMA driver
clk: samsung: s3c64xx: Remove clock aliases of old DMA driver
spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled
ASoC: Samsung: Always select S3C64XX_PL080 when ARCH_S3C64XX is
enabled

 arch/arm/Kconfig                         |   1 +
 arch/arm/mach-s3c64xx/Kconfig            |   7 +-
 arch/arm/mach-s3c64xx/Makefile           |   2 +-
 arch/arm/mach-s3c64xx/clock.c            |  28 +-
 arch/arm/mach-s3c64xx/common.h           |   5 +
 arch/arm/mach-s3c64xx/dma.c              | 753 -------------------------------
 arch/arm/mach-s3c64xx/include/mach/dma.h | 144 ++----
 arch/arm/mach-s3c64xx/pl080.c            | 244 ++++++++++
 arch/arm/plat-samsung/devs.c             |   6 +-
 arch/arm/plat-samsung/s3c-dma-ops.c      |  13 +-
 drivers/clk/samsung/clk-s3c64xx.c        |   4 +-
 drivers/dma/amba-pl08x.c                 | 501 ++++++++++++++------
 drivers/spi/Kconfig                      |   2 +-
 include/linux/amba/pl080.h               |   1 +
 sound/soc/samsung/Kconfig                |   2 +-
 sound/soc/samsung/dma.c                  |   7 +
 16 files changed, 705 insertions(+), 1015 deletions(-)
 delete mode 100644 arch/arm/mach-s3c64xx/dma.c
 create mode 100644 arch/arm/mach-s3c64xx/pl080.c
Signature · 1 line
1.8.3.2
#1 lore raw

PATCH 1/18 dmaengine: PL08x: Refactor pl08x_getbytes_chan() to lower indentation

Further patch will introduce support for PL080S, which requires some things to be done conditionally, thus increasing indentation level of some functions even more.

This patch reduces indentation level of pl08x_getbytes_chan() function by inverting several conditions and returning from function wherever possible.

---
 drivers/dma/amba-pl08x.c | 53 ++++++++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 24 deletions(-)
drivers/dma/amba-pl08x.c +29 -24
index 06fe45c..6a12392 100644
@@ -469,47 +469,52 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
 /* The channel should be paused when calling this */
 static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 {
+	struct pl08x_lli *llis_va;
 	struct pl08x_phy_chan *ch;
+	dma_addr_t llis_bus;
 	struct pl08x_txd *txd;
-	size_t bytes = 0;
+	size_t bytes;
+	int index;
+	u32 clli;
 
 	ch = plchan->phychan;
 	txd = plchan->at;
 
+	if (!ch || !txd)
+		return 0;
+
 	/*
 	 * Follow the LLIs to get the number of remaining
 	 * bytes in the currently active transaction.
 	 */
-	if (ch && txd) {
-		u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
+	clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
 
-		/* First get the remaining bytes in the active transfer */
-		bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
+	/* First get the remaining bytes in the active transfer */
+	bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
 
-		if (clli) {
-			struct pl08x_lli *llis_va = txd->llis_va;
-			dma_addr_t llis_bus = txd->llis_bus;
-			int index;
+	if (!clli)
+		return bytes;
 
-			BUG_ON(clli < llis_bus || clli >= llis_bus +
+	llis_va = txd->llis_va;
+	llis_bus = txd->llis_bus;
+
+	BUG_ON(clli < llis_bus || clli >= llis_bus +
 				sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
 
-			/*
-			 * Locate the next LLI - as this is an array,
-			 * it's simple maths to find.
-			 */
-			index = (clli - llis_bus) / sizeof(struct pl08x_lli);
+	/*
+	 * Locate the next LLI - as this is an array,
+	 * it's simple maths to find.
+	 */
+	index = (clli - llis_bus) / sizeof(struct pl08x_lli);
 
-			for (; index < MAX_NUM_TSFR_LLIS; index++) {
-				bytes += get_bytes_in_cctl(llis_va[index].cctl);
+	for (; index < MAX_NUM_TSFR_LLIS; index++) {
+		bytes += get_bytes_in_cctl(llis_va[index].cctl);
 
-				/*
-				 * A LLI pointer of 0 terminates the LLI list
-				 */
-				if (!llis_va[index].lli)
-					break;
-			}
-		}
+		/*
+		 * A LLI pointer of 0 terminates the LLI list
+		 */
+		if (!llis_va[index].lli)
+			break;
 	}
 
 	return bytes;
Signature · 1 line
1.8.3.2
#2 lore raw

PATCH 2/18 dmaengine: PL08x: Add support for different offset of CONFIG register

In reply to Tomasz Figa

Some variants of PL08x (namely PL080S, found in Samsung S3C64xx SoCs) have CONFIG register at different offset. This patch makes the driver use offset from vendor data struct.

---
 drivers/dma/amba-pl08x.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)
drivers/dma/amba-pl08x.c +18 -12
index 6a12392..2538e05 100644
@@ -102,6 +102,7 @@ struct pl08x_driver_data;
  *	missing
  */
 struct vendor_data {
+	u8 config_offset;
 	u8 channels;
 	bool dualmaster;
 	bool nomadik;
@@ -145,6 +146,7 @@ struct pl08x_bus_data {
 struct pl08x_phy_chan {
 	unsigned int id;
 	void __iomem *base;
+	void __iomem *reg_config;
 	spinlock_t lock;
 	struct pl08x_dma_chan *serving;
 	bool locked;
@@ -334,7 +336,7 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
 {
 	unsigned int val;
 
-	val = readl(ch->base + PL080_CH_CONFIG);
+	val = readl(ch->reg_config);
 	return val & PL080_CONFIG_ACTIVE;
 }
 
@@ -373,7 +375,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 	writel(lli->dst, phychan->base + PL080_CH_DST_ADDR);
 	writel(lli->lli, phychan->base + PL080_CH_LLI);
 	writel(lli->cctl, phychan->base + PL080_CH_CONTROL);
-	writel(txd->ccfg, phychan->base + PL080_CH_CONFIG);
+	writel(txd->ccfg, phychan->reg_config);
 
 	/* Enable the DMA channel */
 	/* Do not access config register until channel shows as disabled */
@@ -381,11 +383,11 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 		cpu_relax();
 
 	/* Do not access config register until channel shows as inactive */
-	val = readl(phychan->base + PL080_CH_CONFIG);
+	val = readl(phychan->reg_config);
 	while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
-		val = readl(phychan->base + PL080_CH_CONFIG);
+		val = readl(phychan->reg_config);
 
-	writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG);
+	writel(val | PL080_CONFIG_ENABLE, phychan->reg_config);
 }
 
 /*
@@ -404,9 +406,9 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
 	int timeout;
 
 	/* Set the HALT bit and wait for the FIFO to drain */
-	val = readl(ch->base + PL080_CH_CONFIG);
+	val = readl(ch->reg_config);
 	val |= PL080_CONFIG_HALT;
-	writel(val, ch->base + PL080_CH_CONFIG);
+	writel(val, ch->reg_config);
 
 	/* Wait for channel inactive */
 	for (timeout = 1000; timeout; timeout--) {
@@ -423,9 +425,9 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
 	u32 val;
 
 	/* Clear the HALT bit */
-	val = readl(ch->base + PL080_CH_CONFIG);
+	val = readl(ch->reg_config);
 	val &= ~PL080_CONFIG_HALT;
-	writel(val, ch->base + PL080_CH_CONFIG);
+	writel(val, ch->reg_config);
 }
 
 /*
@@ -437,12 +439,12 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
 static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
 	struct pl08x_phy_chan *ch)
 {
-	u32 val = readl(ch->base + PL080_CH_CONFIG);
+	u32 val = readl(ch->reg_config);
 
 	val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
 	         PL080_CONFIG_TC_IRQ_MASK);
 
-	writel(val, ch->base + PL080_CH_CONFIG);
+	writel(val, ch->reg_config);
 
 	writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR);
 	writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR);
@@ -1952,6 +1954,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
 		ch->id = i;
 		ch->base = pl08x->base + PL080_Cx_BASE(i);
+		ch->reg_config = ch->base + vd->config_offset;
 		spin_lock_init(&ch->lock);
 
 		/*
@@ -1962,7 +1965,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		if (vd->nomadik) {
 			u32 val;
 
-			val = readl(ch->base + PL080_CH_CONFIG);
+			val = readl(ch->reg_config);
 			if (val & (PL080N_CONFIG_ITPROT | PL080N_CONFIG_SECPROT)) {
 				dev_info(&adev->dev, "physical channel %d reserved for secure access only\n", i);
 				ch->locked = true;
@@ -2043,17 +2046,20 @@ out_no_pl08x:
 
 /* PL080 has 8 channels and the PL080 have just 2 */
 static struct vendor_data vendor_pl080 = {
+	.config_offset = PL080_CH_CONFIG,
 	.channels = 8,
 	.dualmaster = true,
 };
 
 static struct vendor_data vendor_nomadik = {
+	.config_offset = PL080_CH_CONFIG,
 	.channels = 8,
 	.dualmaster = true,
 	.nomadik = true,
 };
 
 static struct vendor_data vendor_pl081 = {
+	.config_offset = PL080_CH_CONFIG,
 	.channels = 2,
 	.dualmaster = false,
 };
Signature · 1 line
1.8.3.2
#3 lore raw

PATCH 3/18 dmaengine: PL08x: Rework LLI handling to be less fragile

In reply to Tomasz Figa

Currently memory allocated for LLIs is casted to an array of structs, which is fragile and also limits the driver to a single, predefined LLI layout, while there are some variants of PL08x, which have more fields in LLI (namely PL080S with its extra CCTL2).

This patch makes LLIs a sequence of 32-bit words, which is just filled with appropriate values in appropriate order and padded with required amount of dummy words (currently zero, but PL080S will make better use of this).

---
 drivers/dma/amba-pl08x.c | 147 ++++++++++++++++++++++++++---------------------
 1 file changed, 82 insertions(+), 65 deletions(-)
drivers/dma/amba-pl08x.c +82 -65
index 2538e05..d3399c2 100644
@@ -108,19 +108,6 @@ struct vendor_data {
 	bool nomadik;
 };
 
-/*
- * PL08X private data structures
- * An LLI struct - see PL08x TRM.  Note that next uses bit[0] as a bus bit,
- * start & end do not - their bus bit info is in cctl.  Also note that these
- * are fixed 32-bit quantities.
- */
-struct pl08x_lli {
-	u32 src;
-	u32 dst;
-	u32 lli;
-	u32 cctl;
-};
-
 /**
  * struct pl08x_bus_data - information of source or destination
  * busses for a transfer
@@ -181,7 +168,7 @@ struct pl08x_txd {
 	struct virt_dma_desc vd;
 	struct list_head dsg_list;
 	dma_addr_t llis_bus;
-	struct pl08x_lli *llis_va;
+	u32 *llis_va;
 	/* Default cctl value for LLIs */
 	u32 cctl;
 	/*
@@ -265,17 +252,27 @@ struct pl08x_driver_data {
 	struct dma_pool *pool;
 	u8 lli_buses;
 	u8 mem_buses;
+	u8 lli_words;
 };
 
 /*
  * PL08X specific defines
  */
 
-/* Size (bytes) of each LLI buffer allocated for one transfer */
-# define PL08X_LLI_TSFR_SIZE	0x2000
+/* The order of words in an LLI. */
+#define PL080_LLI_SRC		0
+#define PL080_LLI_DST		1
+#define PL080_LLI_LLI		2
+#define PL080_LLI_CCTL		3
+
+/* Total words in an LLI. */
+#define PL080_LLI_WORDS		4
 
-/* Maximum times we call dma_pool_alloc on this pool without freeing */
-#define MAX_NUM_TSFR_LLIS	(PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
+/*
+ * Number of LLIs in each LLI buffer allocated for one transfer
+ * (maximum times we call dma_pool_alloc on this pool without freeing)
+ */
+#define MAX_NUM_TSFR_LLIS	512
 #define PL08X_ALIGN		8
 
 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
@@ -340,6 +337,23 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
 	return val & PL080_CONFIG_ACTIVE;
 }
 
+static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
+		struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg)
+{
+	dev_vdbg(&pl08x->adev->dev,
+		"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+		"clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
+		phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
+		lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
+
+	writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR);
+	writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR);
+	writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI);
+	writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL);
+
+	writel(ccfg, phychan->reg_config);
+}
+
 /*
  * Set the initial DMA register values i.e. those for the first LLI
  * The next LLI pointer and the configuration interrupt bit have
@@ -352,7 +366,6 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 	struct pl08x_phy_chan *phychan = plchan->phychan;
 	struct virt_dma_desc *vd = vchan_next_desc(&plchan->vc);
 	struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
-	struct pl08x_lli *lli;
 	u32 val;
 
 	list_del(&txd->vd.node);
@@ -363,19 +376,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 	while (pl08x_phy_channel_busy(phychan))
 		cpu_relax();
 
-	lli = &txd->llis_va[0];
-
-	dev_vdbg(&pl08x->adev->dev,
-		"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
-		"clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
-		phychan->id, lli->src, lli->dst, lli->lli, lli->cctl,
-		txd->ccfg);
-
-	writel(lli->src, phychan->base + PL080_CH_SRC_ADDR);
-	writel(lli->dst, phychan->base + PL080_CH_DST_ADDR);
-	writel(lli->lli, phychan->base + PL080_CH_LLI);
-	writel(lli->cctl, phychan->base + PL080_CH_CONTROL);
-	writel(txd->ccfg, phychan->reg_config);
+	pl08x_write_lli(pl08x, phychan, &txd->llis_va[0], txd->ccfg);
 
 	/* Enable the DMA channel */
 	/* Do not access config register until channel shows as disabled */
@@ -471,12 +472,13 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
 /* The channel should be paused when calling this */
 static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 {
-	struct pl08x_lli *llis_va;
+	struct pl08x_driver_data *pl08x = plchan->host;
+	const u32 *llis_va, *llis_va_limit;
 	struct pl08x_phy_chan *ch;
 	dma_addr_t llis_bus;
 	struct pl08x_txd *txd;
+	u32 llis_max_words;
 	size_t bytes;
-	int index;
 	u32 clli;
 
 	ch = plchan->phychan;
@@ -500,22 +502,25 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	llis_va = txd->llis_va;
 	llis_bus = txd->llis_bus;
 
+	llis_max_words = pl08x->lli_words * MAX_NUM_TSFR_LLIS;
 	BUG_ON(clli < llis_bus || clli >= llis_bus +
-				sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
+						sizeof(u32) * llis_max_words);
 
 	/*
 	 * Locate the next LLI - as this is an array,
 	 * it's simple maths to find.
 	 */
-	index = (clli - llis_bus) / sizeof(struct pl08x_lli);
+	llis_va += (clli - llis_bus) / sizeof(u32);
 
-	for (; index < MAX_NUM_TSFR_LLIS; index++) {
-		bytes += get_bytes_in_cctl(llis_va[index].cctl);
+	llis_va_limit = llis_va + llis_max_words;
+
+	for (; llis_va < llis_va_limit; llis_va += pl08x->lli_words) {
+		bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
 
 		/*
 		 * A LLI pointer of 0 terminates the LLI list
 		 */
-		if (!llis_va[index].lli)
+		if (!llis_va[PL080_LLI_LLI])
 			break;
 	}
 
@@ -771,20 +776,24 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
 /*
  * Fills in one LLI for a certain transfer descriptor and advance the counter
  */
-static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
-	int num_llis, int len, u32 cctl)
+static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
+				    struct pl08x_lli_build_data *bd,
+				    int num_llis, int len, u32 cctl)
 {
-	struct pl08x_lli *llis_va = bd->txd->llis_va;
+	u32 offset = num_llis * pl08x->lli_words;
+	u32 *llis_va = bd->txd->llis_va + offset;
 	dma_addr_t llis_bus = bd->txd->llis_bus;
 
 	BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
 
-	llis_va[num_llis].cctl = cctl;
-	llis_va[num_llis].src = bd->srcbus.addr;
-	llis_va[num_llis].dst = bd->dstbus.addr;
-	llis_va[num_llis].lli = llis_bus + (num_llis + 1) *
-		sizeof(struct pl08x_lli);
-	llis_va[num_llis].lli |= bd->lli_bus;
+	/* Advance the offset to next LLI. */
+	offset += pl08x->lli_words;
+
+	llis_va[PL080_LLI_SRC] = bd->srcbus.addr;
+	llis_va[PL080_LLI_DST] = bd->dstbus.addr;
+	llis_va[PL080_LLI_LLI] = (llis_bus + sizeof(u32) * offset);
+	llis_va[PL080_LLI_LLI] |= bd->lli_bus;
+	llis_va[PL080_LLI_CCTL] = cctl;
 
 	if (cctl & PL080_CONTROL_SRC_INCR)
 		bd->srcbus.addr += len;
@@ -796,11 +805,12 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
 	bd->remainder -= len;
 }
 
-static inline void prep_byte_width_lli(struct pl08x_lli_build_data *bd,
-		u32 *cctl, u32 len, int num_llis, size_t *total_bytes)
+static inline void prep_byte_width_lli(struct pl08x_driver_data *pl08x,
+			struct pl08x_lli_build_data *bd, u32 *cctl, u32 len,
+			int num_llis, size_t *total_bytes)
 {
 	*cctl = pl08x_cctl_bits(*cctl, 1, 1, len);
-	pl08x_fill_lli_for_desc(bd, num_llis, len, *cctl);
+	pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl);
 	(*total_bytes) += len;
 }
 
@@ -817,7 +827,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 	int num_llis = 0;
 	u32 cctl, early_bytes = 0;
 	size_t max_bytes_per_lli, total_bytes;
-	struct pl08x_lli *llis_va;
+	u32 *llis_va, *last_lli;
 	struct pl08x_sg *dsg;
 
 	txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus);
@@ -904,7 +914,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
 			cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
 					bd.dstbus.buswidth, 0);
-			pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl);
+			pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
+					0, cctl);
 			break;
 		}
 
@@ -926,8 +937,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 			dev_vdbg(&pl08x->adev->dev,
 				"%s byte width LLIs (remain 0x%08x)\n",
 				__func__, bd.remainder);
-			prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++,
-				&total_bytes);
+			prep_byte_width_lli(pl08x, &bd, &cctl, early_bytes,
+				num_llis++, &total_bytes);
 		}
 
 		if (bd.remainder) {
@@ -983,7 +994,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
 				cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
 					bd.dstbus.buswidth, tsize);
-				pl08x_fill_lli_for_desc(&bd, num_llis++,
+				pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
 						lli_len, cctl);
 				total_bytes += lli_len;
 			}
@@ -995,8 +1006,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 				dev_vdbg(&pl08x->adev->dev,
 					"%s align with boundary, send odd bytes (remain %zu)\n",
 					__func__, bd.remainder);
-				prep_byte_width_lli(&bd, &cctl, bd.remainder,
-						num_llis++, &total_bytes);
+				prep_byte_width_lli(pl08x, &bd, &cctl,
+					bd.remainder, num_llis++, &total_bytes);
 			}
 		}
 
@@ -1010,16 +1021,17 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 		if (num_llis >= MAX_NUM_TSFR_LLIS) {
 			dev_err(&pl08x->adev->dev,
 				"%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
-				__func__, (u32) MAX_NUM_TSFR_LLIS);
+				__func__, MAX_NUM_TSFR_LLIS);
 			return 0;
 		}
 	}
 
 	llis_va = txd->llis_va;
+	last_lli = llis_va + (num_llis - 1) * pl08x->lli_words;
 	/* The final LLI terminates the LLI. */
-	llis_va[num_llis - 1].lli = 0;
+	last_lli[PL080_LLI_LLI] = 0;
 	/* The final LLI element shall also fire an interrupt. */
-	llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+	last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
 
 #ifdef VERBOSE_DEBUG
 	{
@@ -1031,9 +1043,10 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 		for (i = 0; i < num_llis; i++) {
 			dev_vdbg(&pl08x->adev->dev,
 				 "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-				 i, &llis_va[i], llis_va[i].src,
-				 llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl
-				);
+				 i, llis_va, llis_va[PL080_LLI_SRC],
+				 llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+				 llis_va[PL080_LLI_CCTL]);
+			llis_va += pl08x->lli_words;
 		}
 	}
 #endif
@@ -1853,6 +1866,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	struct pl08x_driver_data *pl08x;
 	const struct vendor_data *vd = id->data;
+	u32 tsfr_size;
 	int ret = 0;
 	int i;
 
@@ -1909,9 +1923,12 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		pl08x->mem_buses = pl08x->pd->mem_buses;
 	}
 
+	pl08x->lli_words = PL080_LLI_WORDS;
+	tsfr_size = MAX_NUM_TSFR_LLIS * pl08x->lli_words * sizeof(u32);
+
 	/* A DMA memory pool for LLIs, align on 1-byte boundary */
 	pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
-			PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
+						tsfr_size, PL08X_ALIGN, 0);
 	if (!pl08x->pool) {
 		ret = -ENOMEM;
 		goto out_no_lli_pool;
Signature · 1 line
1.8.3.2
Reviewed-by on v1 3/18
#4 lore raw

Re: [PATCH 03/18] dmaengine: PL08x: Rework LLI handling to be less fragile

Quoted 5 lines · Tomasz Figa

Currently memory allocated for LLIs is casted to an array of structs, which is fragile and also limits the driver to a single, predefined LLI layout, while there are some variants of PL08x, which have more fields in LLI (namely PL080S with its extra CCTL2).

Quoted 7 lines

This patch makes LLIs a sequence of 32-bit words, which is just filled with appropriate values in appropriate order and padded with required amount of dummy words (currently zero, but PL080S will make better use of this).

Yes exactly like this :-)

Yours,
Linus Walleij

#5 lore raw

PATCH 4/18 dmaengine: PL08x: Move LLI dumping code into separate function

In reply to Tomasz Figa

This patch refactors debugging code that dumps LLI entries by moving it into separate function, which is stubbed when VERBOSE_DEBUG is not selected. This allows us to get rid of the ugly ifdef from the body of pl08x_fill_llis_for_desc().

No functional change is introduced by this patch.

---
 drivers/dma/amba-pl08x.c | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)
drivers/dma/amba-pl08x.c +24 -17
index d3399c2..1fa05d6 100644
@@ -814,6 +814,29 @@ static inline void prep_byte_width_lli(struct pl08x_driver_data *pl08x,
 	(*total_bytes) += len;
 }
 
+#ifdef VERBOSE_DEBUG
+static void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
+			   const u32 *llis_va, int num_llis)
+{
+	int i;
+
+	dev_vdbg(&pl08x->adev->dev,
+		"%-3s %-9s  %-10s %-10s %-10s %s\n",
+		"lli", "", "csrc", "cdst", "clli", "cctl");
+	for (i = 0; i < num_llis; i++) {
+		dev_vdbg(&pl08x->adev->dev,
+			"%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			i, llis_va, llis_va[PL080_LLI_SRC],
+			llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+			llis_va[PL080_LLI_CCTL]);
+		llis_va += pl08x->lli_words;
+	}
+}
+#else
+static inline void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
+				  const u32 *llis_va, int num_llis) {}
+#endif
+
 /*
  * This fills in the table of LLIs for the transfer descriptor
  * Note that we assume we never have to change the burst sizes
@@ -1033,23 +1056,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 	/* The final LLI element shall also fire an interrupt. */
 	last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
 
-#ifdef VERBOSE_DEBUG
-	{
-		int i;
-
-		dev_vdbg(&pl08x->adev->dev,
-			 "%-3s %-9s  %-10s %-10s %-10s %s\n",
-			 "lli", "", "csrc", "cdst", "clli", "cctl");
-		for (i = 0; i < num_llis; i++) {
-			dev_vdbg(&pl08x->adev->dev,
-				 "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-				 i, llis_va, llis_va[PL080_LLI_SRC],
-				 llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
-				 llis_va[PL080_LLI_CCTL]);
-			llis_va += pl08x->lli_words;
-		}
-	}
-#endif
+	pl08x_dump_lli(pl08x, llis_va, num_llis);
 
 	return num_llis;
 }
Signature · 1 line
1.8.3.2
Reviewed-by on v1 4/18
#6 lore raw

Re: [PATCH 04/18] dmaengine: PL08x: Move LLI dumping code into separate function

Quoted 8 lines · Tomasz Figa

This patch refactors debugging code that dumps LLI entries by moving it into separate function, which is stubbed when VERBOSE_DEBUG is not selected. This allows us to get rid of the ugly ifdef from the body of pl08x_fill_llis_for_desc().

No functional change is introduced by this patch.

Yours,
Linus Walleij

#7 lore raw

PATCH 5/18 dmaengine: PL08x: Add support for PL080S variant

In reply to Tomasz Figa

PL080S is a modified version of PL080 that can be found on Samsung SoCs, such as S3C6400 and S3C6410.

It has different offset of CONFIG register, separate CONTROL1 register that holds transfer size and larger maximum transfer size.

---
 drivers/dma/amba-pl08x.c   | 145 ++++++++++++++++++++++++++++++++++++---------
 include/linux/amba/pl080.h |   1 +
 2 files changed, 119 insertions(+), 27 deletions(-)
drivers/dma/amba-pl08x.c +118 -27
index 1fa05d6..75915be 100644
@@ -24,6 +24,7 @@
  *
  * Documentation: ARM DDI 0196G == PL080
  * Documentation: ARM DDI 0218E == PL081
+ * Documentation: S3C6410 User's Manual == PL080S
  *
  * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any
  * channel.
@@ -36,6 +37,14 @@
  *
  * The PL080 has a dual bus master, PL081 has a single master.
  *
+ * PL080S is a version modified by Samsung and used in S3C64xx SoCs.
+ * It differs in following aspects:
+ * - CH_CONFIG register at different offset,
+ * - separate CH_CONTROL2 register for transfer size,
+ * - bigger maximum transfer size,
+ * - 8-word aligned LLI, instead of 4-word, due to extra CCTL2 word,
+ * - no support for peripheral flow control.
+ *
  * Memory to peripheral transfer may be visualized as
  *	Get data from memory to DMAC
  *	Until no data left
@@ -64,10 +73,7 @@
  *  - Peripheral flow control: the transfer size is ignored (and should be
  *    zero).  The data is transferred from the current LLI entry, until
  *    after the final transfer signalled by LBREQ or LSREQ.  The DMAC
- *    will then move to the next LLI entry.
- *
- * Global TODO:
- * - Break out common code from arch/arm/mach-s3c64xx and share
+ *    will then move to the next LLI entry. Unsupported by PL080S.
  */
 #include <linux/amba/bus.h>
 #include <linux/amba/pl08x.h>
@@ -100,12 +106,15 @@ struct pl08x_driver_data;
  * @nomadik: whether the channels have Nomadik security extension bits
  *	that need to be checked for permission before use and some registers are
  *	missing
+ * @pl080s: whether this version is a PL080S, which has separate register and
+ *	LLI word for transfer size.
  */
 struct vendor_data {
 	u8 config_offset;
 	u8 channels;
 	bool dualmaster;
 	bool nomadik;
+	bool pl080s;
 };
 
 /**
@@ -264,9 +273,11 @@ struct pl08x_driver_data {
 #define PL080_LLI_DST		1
 #define PL080_LLI_LLI		2
 #define PL080_LLI_CCTL		3
+#define PL080S_LLI_CCTL2	4
 
 /* Total words in an LLI. */
 #define PL080_LLI_WORDS		4
+#define PL080S_LLI_WORDS	8
 
 /*
  * Number of LLIs in each LLI buffer allocated for one transfer
@@ -340,17 +351,29 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
 static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
 		struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg)
 {
-	dev_vdbg(&pl08x->adev->dev,
-		"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
-		"clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
-		phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
-		lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
+	if (pl08x->vd->pl080s)
+		dev_vdbg(&pl08x->adev->dev,
+			"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+			"clli=0x%08x, cctl=0x%08x, cctl2=0x%08x, ccfg=0x%08x\n",
+			phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
+			lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL],
+			lli[PL080S_LLI_CCTL2], ccfg);
+	else
+		dev_vdbg(&pl08x->adev->dev,
+			"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+			"clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
+			phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
+			lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
 
 	writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR);
 	writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR);
 	writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI);
 	writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL);
 
+	if (pl08x->vd->pl080s)
+		writel_relaxed(lli[PL080S_LLI_CCTL2],
+				phychan->base + PL080S_CH_CONTROL2);
+
 	writel(ccfg, phychan->reg_config);
 }
 
@@ -469,6 +492,24 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
 	return bytes;
 }
 
+static inline u32 get_bytes_in_cctl_pl080s(u32 cctl, u32 cctl1)
+{
+	/* The source width defines the number of bytes */
+	u32 bytes = cctl1 & PL080S_CONTROL_TRANSFER_SIZE_MASK;
+
+	switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
+	case PL080_WIDTH_8BIT:
+		break;
+	case PL080_WIDTH_16BIT:
+		bytes *= 2;
+		break;
+	case PL080_WIDTH_32BIT:
+		bytes *= 4;
+		break;
+	}
+	return bytes;
+}
+
 /* The channel should be paused when calling this */
 static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 {
@@ -494,7 +535,12 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
 
 	/* First get the remaining bytes in the active transfer */
-	bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
+	if (pl08x->vd->pl080s)
+		bytes = get_bytes_in_cctl_pl080s(
+				readl(ch->base + PL080_CH_CONTROL),
+				readl(ch->base + PL080S_CH_CONTROL2));
+	else
+		bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
 
 	if (!clli)
 		return bytes;
@@ -515,7 +561,12 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	llis_va_limit = llis_va + llis_max_words;
 
 	for (; llis_va < llis_va_limit; llis_va += pl08x->lli_words) {
-		bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
+		if (pl08x->vd->pl080s)
+			bytes += get_bytes_in_cctl_pl080s(
+						llis_va[PL080_LLI_CCTL],
+						llis_va[PL080S_LLI_CCTL2]);
+		else
+			bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
 
 		/*
 		 * A LLI pointer of 0 terminates the LLI list
@@ -778,7 +829,7 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
  */
 static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
 				    struct pl08x_lli_build_data *bd,
-				    int num_llis, int len, u32 cctl)
+				    int num_llis, int len, u32 cctl, u32 cctl2)
 {
 	u32 offset = num_llis * pl08x->lli_words;
 	u32 *llis_va = bd->txd->llis_va + offset;
@@ -794,6 +845,8 @@ static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
 	llis_va[PL080_LLI_LLI] = (llis_bus + sizeof(u32) * offset);
 	llis_va[PL080_LLI_LLI] |= bd->lli_bus;
 	llis_va[PL080_LLI_CCTL] = cctl;
+	if (pl08x->vd->pl080s)
+		llis_va[PL080S_LLI_CCTL2] = cctl2;
 
 	if (cctl & PL080_CONTROL_SRC_INCR)
 		bd->srcbus.addr += len;
@@ -810,7 +863,7 @@ static inline void prep_byte_width_lli(struct pl08x_driver_data *pl08x,
 			int num_llis, size_t *total_bytes)
 {
 	*cctl = pl08x_cctl_bits(*cctl, 1, 1, len);
-	pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl);
+	pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl, len);
 	(*total_bytes) += len;
 }
 
@@ -820,16 +873,31 @@ static void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
 {
 	int i;
 
-	dev_vdbg(&pl08x->adev->dev,
-		"%-3s %-9s  %-10s %-10s %-10s %s\n",
-		"lli", "", "csrc", "cdst", "clli", "cctl");
-	for (i = 0; i < num_llis; i++) {
+	if (pl08x->vd->pl080s) {
 		dev_vdbg(&pl08x->adev->dev,
-			"%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-			i, llis_va, llis_va[PL080_LLI_SRC],
-			llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
-			llis_va[PL080_LLI_CCTL]);
-		llis_va += pl08x->lli_words;
+			"%-3s %-9s  %-10s %-10s %-10s %-10s %s\n",
+			"lli", "", "csrc", "cdst", "clli", "cctl", "cctl2");
+		for (i = 0; i < num_llis; i++) {
+			dev_vdbg(&pl08x->adev->dev,
+				"%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+				i, llis_va, llis_va[PL080_LLI_SRC],
+				llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+				llis_va[PL080_LLI_CCTL],
+				llis_va[PL080S_LLI_CCTL2]);
+			llis_va += pl08x->lli_words;
+		}
+	} else {
+		dev_vdbg(&pl08x->adev->dev,
+			"%-3s %-9s  %-10s %-10s %-10s %s\n",
+			"lli", "", "csrc", "cdst", "clli", "cctl");
+		for (i = 0; i < num_llis; i++) {
+			dev_vdbg(&pl08x->adev->dev,
+				"%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+				i, llis_va, llis_va[PL080_LLI_SRC],
+				llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+				llis_va[PL080_LLI_CCTL]);
+			llis_va += pl08x->lli_words;
+		}
 	}
 }
 #else
@@ -938,7 +1006,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 			cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
 					bd.dstbus.buswidth, 0);
 			pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
-					0, cctl);
+					0, cctl, 0);
 			break;
 		}
 
@@ -1018,7 +1086,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 				cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
 					bd.dstbus.buswidth, tsize);
 				pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
-						lli_len, cctl);
+						lli_len, cctl, tsize);
 				total_bytes += lli_len;
 			}
 
@@ -1332,6 +1400,7 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 				  struct dma_slave_config *config)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
 
 	if (!plchan->slave)
 		return -EINVAL;
@@ -1341,6 +1410,13 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 	    config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
 		return -EINVAL;
 
+	if (config->device_fc && pl08x->vd->pl080s) {
+		dev_err(&pl08x->adev->dev,
+			"%s: PL080S does not support peripheral flow control\n",
+			__func__);
+		return -EINVAL;
+	}
+
 	plchan->cfg = *config;
 
 	return 0;
@@ -1930,7 +2006,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		pl08x->mem_buses = pl08x->pd->mem_buses;
 	}
 
-	pl08x->lli_words = PL080_LLI_WORDS;
+	if (vd->pl080s)
+		pl08x->lli_words = PL080S_LLI_WORDS;
+	else
+		pl08x->lli_words = PL080_LLI_WORDS;
 	tsfr_size = MAX_NUM_TSFR_LLIS * pl08x->lli_words * sizeof(u32);
 
 	/* A DMA memory pool for LLIs, align on 1-byte boundary */
@@ -2040,8 +2119,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
 	amba_set_drvdata(adev, pl08x);
 	init_pl08x_debugfs(pl08x);
-	dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n",
-		 amba_part(adev), amba_rev(adev),
+	dev_info(&pl08x->adev->dev, "DMA: PL%03x%s rev%u at 0x%08llx irq %d\n",
+		 amba_part(adev), pl08x->vd->pl080s ? "s" : "", amba_rev(adev),
 		 (unsigned long long)adev->res.start, adev->irq[0]);
 
 	return 0;
@@ -2082,6 +2161,12 @@ static struct vendor_data vendor_nomadik = {
 	.nomadik = true,
 };
 
+static struct vendor_data vendor_pl080s = {
+	.config_offset = PL080S_CH_CONFIG,
+	.channels = 8,
+	.pl080s = true,
+};
+
 static struct vendor_data vendor_pl081 = {
 	.config_offset = PL080_CH_CONFIG,
 	.channels = 2,
@@ -2089,6 +2174,12 @@ static struct vendor_data vendor_pl081 = {
 };
 
 static struct amba_id pl08x_ids[] = {
+	/* Samsung PL080S variant */
+	{
+		.id	= 0x0a141080,
+		.mask	= 0xffffffff,
+		.data	= &vendor_pl080s,
+	},
 	/* PL080 */
 	{
 		.id	= 0x00041080,
include/linux/amba/pl080.h +1 -0
index 3e7b62f..91b84a7 100644
@@ -87,6 +87,7 @@
 #define PL080_CONTROL_SB_SIZE_MASK		(0x7 << 12)
 #define PL080_CONTROL_SB_SIZE_SHIFT		(12)
 #define PL080_CONTROL_TRANSFER_SIZE_MASK	(0xfff << 0)
+#define PL080S_CONTROL_TRANSFER_SIZE_MASK	(0x1ffffff << 0)
 #define PL080_CONTROL_TRANSFER_SIZE_SHIFT	(0)
 
 #define PL080_BSIZE_1				(0x0)
Signature · 1 line
1.8.3.2
#8 lore raw

PATCH 6/18 dmaengine: PL08x: Add support for different maximum transfer size

In reply to Tomasz Figa

PL080S has separate register to store transfer size in, allowing single transfer to be much larger than in standard PL080.

This patch makes the amba-pl08x driver aware of this and removes writing transfer size to reserved bits of CH_CONTROL register on PL080S, which was not a problem witn transfer sizes fitting the original bitfield of PL080, but now would overwrite other fields.

Acked by: Vinod Koul <[email protected]>

---
 drivers/dma/amba-pl08x.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/dma/amba-pl08x.c +7 -1
index 75915be..4e4c3df 100644
@@ -115,6 +115,7 @@ struct vendor_data {
 	bool dualmaster;
 	bool nomadik;
 	bool pl080s;
+	u32 max_transfer_size;
 };
 
 /**
@@ -783,6 +784,7 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
 		break;
 	}
 
+	tsize &= PL080_CONTROL_TRANSFER_SIZE_MASK;
 	retbits |= tsize << PL080_CONTROL_TRANSFER_SIZE_SHIFT;
 	return retbits;
 }
@@ -1050,7 +1052,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 			 * MIN(buswidths)
 			 */
 			max_bytes_per_lli = bd.srcbus.buswidth *
-				PL080_CONTROL_TRANSFER_SIZE_MASK;
+						pl08x->vd->max_transfer_size;
 			dev_vdbg(&pl08x->adev->dev,
 				"%s max bytes per lli = %zu\n",
 				__func__, max_bytes_per_lli);
@@ -2152,6 +2154,7 @@ static struct vendor_data vendor_pl080 = {
 	.config_offset = PL080_CH_CONFIG,
 	.channels = 8,
 	.dualmaster = true,
+	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct vendor_data vendor_nomadik = {
@@ -2159,18 +2162,21 @@ static struct vendor_data vendor_nomadik = {
 	.channels = 8,
 	.dualmaster = true,
 	.nomadik = true,
+	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct vendor_data vendor_pl080s = {
 	.config_offset = PL080S_CH_CONFIG,
 	.channels = 8,
 	.pl080s = true,
+	.max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct vendor_data vendor_pl081 = {
 	.config_offset = PL080_CH_CONFIG,
 	.channels = 2,
 	.dualmaster = false,
+	.max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct amba_id pl08x_ids[] = {
Signature · 1 line
1.8.3.2
#9 lore raw

PATCH 7/18 dmaengine: PL08x: Fix reading the byte count in cctl

In reply to Tomasz Figa

From: Alban Bedel <[email protected]>

There are more fields than just SWIDTH in CH_CONTROL register, so read register value must be masked in addition to shifting.

---
 drivers/dma/amba-pl08x.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/dma/amba-pl08x.c +4 -0
index 4e4c3df..6b9cba2 100644
@@ -480,6 +480,8 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
 	/* The source width defines the number of bytes */
 	u32 bytes = cctl & PL080_CONTROL_TRANSFER_SIZE_MASK;
 
+	cctl &= PL080_CONTROL_SWIDTH_MASK;
+
 	switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
 	case PL080_WIDTH_8BIT:
 		break;
@@ -498,6 +500,8 @@ static inline u32 get_bytes_in_cctl_pl080s(u32 cctl, u32 cctl1)
 	/* The source width defines the number of bytes */
 	u32 bytes = cctl1 & PL080S_CONTROL_TRANSFER_SIZE_MASK;
 
+	cctl &= PL080_CONTROL_SWIDTH_MASK;
+
 	switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
 	case PL080_WIDTH_8BIT:
 		break;
Signature · 1 line
1.8.3.2
#10 lore raw

PATCH 8/18 dmaengine: PL08x: Add cyclic transfer support

In reply to Tomasz Figa

From: Alban Bedel <[email protected]>

Many audio interface drivers require support of cyclic transfers to work correctly, for example Samsung ASoC DMA driver. This patch adds support for cyclic transfers to the amba-pl08x driver.

[tfiga: Rebase and slightly beautify the original patch.]
---
 drivers/dma/amba-pl08x.c | 147 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 118 insertions(+), 29 deletions(-)
drivers/dma/amba-pl08x.c +118 -29
index 6b9cba2..cd29434 100644
@@ -173,6 +173,7 @@ struct pl08x_sg {
  * @ccfg: config reg values for current txd
  * @done: this marks completed descriptors, which should not have their
  *   mux released.
+ * @cyclic: indicate cyclic transfers
  */
 struct pl08x_txd {
 	struct virt_dma_desc vd;
@@ -187,6 +188,7 @@ struct pl08x_txd {
 	 */
 	u32 ccfg;
 	bool done;
+	bool cyclic;
 };
 
 /**
@@ -574,9 +576,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 			bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
 
 		/*
-		 * A LLI pointer of 0 terminates the LLI list
+		 * A LLI pointer going backward terminates the LLI list
 		 */
-		if (!llis_va[PL080_LLI_LLI])
+		if (llis_va[PL080_LLI_LLI] <= clli)
 			break;
 	}
 
@@ -1125,10 +1127,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
 	llis_va = txd->llis_va;
 	last_lli = llis_va + (num_llis - 1) * pl08x->lli_words;
-	/* The final LLI terminates the LLI. */
-	last_lli[PL080_LLI_LLI] = 0;
-	/* The final LLI element shall also fire an interrupt. */
-	last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
+
+	if (txd->cyclic) {
+		/* Link back to the first LLI. */
+		last_lli[PL080_LLI_LLI] = txd->llis_bus | bd.lli_bus;
+	} else {
+		/* The final LLI terminates the LLI. */
+		last_lli[PL080_LLI_LLI] = 0;
+		/* The final LLI element shall also fire an interrupt. */
+		last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
+	}
 
 	pl08x_dump_lli(pl08x, llis_va, num_llis);
 
@@ -1513,25 +1521,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
 
-static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
-		struct dma_chan *chan, struct scatterlist *sgl,
-		unsigned int sg_len, enum dma_transfer_direction direction,
-		unsigned long flags, void *context)
+static struct pl08x_txd *pl08x_init_txd(
+		struct dma_chan *chan,
+		enum dma_transfer_direction direction,
+		dma_addr_t *slave_addr)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
 	struct pl08x_driver_data *pl08x = plchan->host;
 	struct pl08x_txd *txd;
-	struct pl08x_sg *dsg;
-	struct scatterlist *sg;
 	enum dma_slave_buswidth addr_width;
-	dma_addr_t slave_addr;
 	int ret, tmp;
 	u8 src_buses, dst_buses;
 	u32 maxburst, cctl;
 
-	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
-			__func__, sg_dma_len(sgl), plchan->name);
-
 	txd = pl08x_get_txd(plchan);
 	if (!txd) {
 		dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
@@ -1545,14 +1547,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	 */
 	if (direction == DMA_MEM_TO_DEV) {
 		cctl = PL080_CONTROL_SRC_INCR;
-		slave_addr = plchan->cfg.dst_addr;
+		*slave_addr = plchan->cfg.dst_addr;
 		addr_width = plchan->cfg.dst_addr_width;
 		maxburst = plchan->cfg.dst_maxburst;
 		src_buses = pl08x->mem_buses;
 		dst_buses = plchan->cd->periph_buses;
 	} else if (direction == DMA_DEV_TO_MEM) {
 		cctl = PL080_CONTROL_DST_INCR;
-		slave_addr = plchan->cfg.src_addr;
+		*slave_addr = plchan->cfg.src_addr;
 		addr_width = plchan->cfg.src_addr_width;
 		maxburst = plchan->cfg.src_maxburst;
 		src_buses = plchan->cd->periph_buses;
@@ -1601,24 +1603,107 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	else
 		txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT;
 
+	return txd;
+}
+
+static int pl08x_tx_add_sg(struct pl08x_txd *txd,
+			   enum dma_transfer_direction direction,
+			   dma_addr_t slave_addr,
+			   dma_addr_t buf_addr,
+			   unsigned int len)
+{
+	struct pl08x_sg *dsg;
+
+	dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
+	if (!dsg)
+		return -ENOMEM;
+
+	list_add_tail(&dsg->node, &txd->dsg_list);
+
+	dsg->len = len;
+	if (direction == DMA_MEM_TO_DEV) {
+		dsg->src_addr = buf_addr;
+		dsg->dst_addr = slave_addr;
+	} else {
+		dsg->src_addr = slave_addr;
+		dsg->dst_addr = buf_addr;
+	}
+
+	return 0;
+}
+
+static struct dma_async_tx_descriptor *pl08x_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 pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_txd *txd;
+	struct scatterlist *sg;
+	int ret, tmp;
+	dma_addr_t slave_addr;
+
+	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+			__func__, sg_dma_len(sgl), plchan->name);
+
+	txd = pl08x_init_txd(chan, direction, &slave_addr);
+	if (!txd)
+		return NULL;
+
 	for_each_sg(sgl, sg, sg_len, tmp) {
-		dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
-		if (!dsg) {
+		ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+				      sg_dma_address(sg),
+				      sg_dma_len(sg));
+		if (ret) {
 			pl08x_release_mux(plchan);
 			pl08x_free_txd(pl08x, txd);
 			dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n",
 					__func__);
 			return NULL;
 		}
-		list_add_tail(&dsg->node, &txd->dsg_list);
+	}
 
-		dsg->len = sg_dma_len(sg);
-		if (direction == DMA_MEM_TO_DEV) {
-			dsg->src_addr = sg_dma_address(sg);
-			dsg->dst_addr = slave_addr;
-		} else {
-			dsg->src_addr = slave_addr;
-			dsg->dst_addr = sg_dma_address(sg);
+	ret = pl08x_fill_llis_for_desc(plchan->host, txd);
+	if (!ret) {
+		pl08x_release_mux(plchan);
+		pl08x_free_txd(pl08x, txd);
+		return NULL;
+	}
+
+	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+		size_t period_len, enum dma_transfer_direction direction,
+		unsigned long flags, void *context)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_txd *txd;
+	int ret, tmp;
+	dma_addr_t slave_addr;
+
+	dev_dbg(&pl08x->adev->dev,
+		"%s prepare cyclic transaction of %d/%d bytes %s %s\n",
+		__func__, period_len, buf_len,
+		direction == DMA_MEM_TO_DEV ? "to" : "from",
+		plchan->name);
+
+	txd = pl08x_init_txd(chan, direction, &slave_addr);
+	if (!txd)
+		return NULL;
+
+	txd->cyclic = true;
+	txd->cctl |= PL080_CONTROL_TC_IRQ_EN;
+	for (tmp = 0; tmp < buf_len; tmp += period_len) {
+		ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+				      buf_addr + tmp, period_len);
+		if (ret) {
+			pl08x_release_mux(plchan);
+			pl08x_free_txd(pl08x, txd);
+			return NULL;
 		}
 	}
 
@@ -1761,7 +1846,9 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 
 			spin_lock(&plchan->vc.lock);
 			tx = plchan->at;
-			if (tx) {
+			if (tx && tx->cyclic) {
+				vchan_cyclic_callback(&tx->vd);
+			} else if (tx) {
 				plchan->at = NULL;
 				/*
 				 * This descriptor is done, release its mux
@@ -1983,6 +2070,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
 	/* Initialize slave engine */
 	dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+	dma_cap_set(DMA_CYCLIC, pl08x->slave.cap_mask);
 	pl08x->slave.dev = &adev->dev;
 	pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
 	pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
@@ -1990,6 +2078,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 	pl08x->slave.device_tx_status = pl08x_dma_tx_status;
 	pl08x->slave.device_issue_pending = pl08x_issue_pending;
 	pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+	pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
 	pl08x->slave.device_control = pl08x_control;
 
 	/* Get the platform data */
Signature · 1 line
1.8.3.2
#11 lore raw

PATCH 9/18 ASoC: Samsung: Do not queue cyclic buffers multiple times

In reply to Tomasz Figa

The legacy S3C-DMA API required every period of a cyclic buffer to be queued separately. After conversion of Samsung ASoC to Samsung DMA wrappers somebody made an assumption that the same is needed for DMA engine API, which is not true.

In effect, Samsung ASoC DMA code was queuing the whole cyclic buffer multiple times with a shift of one period per iteration, leading to:
a) severe memory waste - up to 13x times more DMA transfer descriptors are allocated than needed,
b) possible memory corruption, because further cyclic buffers were out of the original buffers, due to the offset.

This patch fixes this problem by making the legacy S3C-DMA API use the same semantics as DMA engine (the whole cyclic buffer is enqueued at once) and modifying users of Samsung DMA wrappers in cyclic mode to behave appropriately.

---
 arch/arm/plat-samsung/s3c-dma-ops.c | 13 +++++++++++--
 sound/soc/samsung/dma.c             |  7 +++++++
 2 files changed, 18 insertions(+), 2 deletions(-)
arch/arm/plat-samsung/s3c-dma-ops.c +11 -2
index 0cc40ae..98b10ba 100644
@@ -82,7 +82,8 @@ static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
 static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
 {
 	struct cb_data *data;
-	int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
+	dma_addr_t pos = param->buf;
+	dma_addr_t end = param->buf + param->len;
 
 	list_for_each_entry(data, &dma_list, node)
 		if (data->ch == ch)
@@ -94,7 +95,15 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
 		data->fp_param = param->fp_param;
 	}
 
-	s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
+	if (param->cap != DMA_CYCLIC) {
+		s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
+		return 0;
+	}
+
+	while (pos < end) {
+		s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
+		pos += param->period;
+	}
 
 	return 0;
 }
sound/soc/samsung/dma.c +7 -0
index 21b7926..6e2b2b4 100644
@@ -90,6 +90,13 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
 	dma_info.period = prtd->dma_period;
 	dma_info.len = prtd->dma_period*limit;
 
+	if (dma_info.cap == DMA_CYCLIC) {
+		dma_info.buf = pos;
+		prtd->params->ops->prepare(prtd->params->ch, &dma_info);
+		prtd->dma_loaded += limit;
+		return;
+	}
+
 	while (prtd->dma_loaded < limit) {
 		pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
 
Signature · 1 line
1.8.3.2
#12 lore raw

Re: [PATCH 09/18] ASoC: Samsung: Do not queue cyclic buffers multiple times

Quoted 12 lines · Tomasz Figa

The legacy S3C-DMA API required every period of a cyclic buffer to be queued separately. After conversion of Samsung ASoC to Samsung DMA wrappers somebody made an assumption that the same is needed for DMA engine API, which is not true.

In effect, Samsung ASoC DMA code was queuing the whole cyclic buffer multiple times with a shift of one period per iteration, leading to:
a) severe memory waste - up to 13x times more DMA transfer descriptors are allocated than needed,
b) possible memory corruption, because further cyclic buffers were out of the original buffers, due to the offset.

Quoted 7 lines

This patch fixes this problem by making the legacy S3C-DMA API use the same semantics as DMA engine (the whole cyclic buffer is enqueued at once) and modifying users of Samsung DMA wrappers in cyclic mode to behave appropriately.

If patch 1 thru 9 are uncontroversial now, maybe Vinod can apply these for v3.12 so we can get less noise and risk of collissions in the next merge window?

Just an idea.

Yours,
Linus Walleij

#13 lore raw

Re: [PATCH 09/18] ASoC: Samsung: Do not queue cyclic buffers multiple times

Quoted 1 line · On Wednesday 28 of August 2013 09:06:27 Linus Walleij wrote:

On Sun, Aug 11, 2013 at 7:59 PM, Tomasz Figa <[email protected]>

Quoted 23 lines · wrote:
Quoted 23 lines

The legacy S3C-DMA API required every period of a cyclic buffer to be queued separately. After conversion of Samsung ASoC to Samsung DMA wrappers somebody made an assumption that the same is needed for DMA engine API, which is not true.

In effect, Samsung ASoC DMA code was queuing the whole cyclic buffer

multiple times with a shift of one period per iteration, leading to:
a) severe memory waste - up to 13x times more DMA transfer descriptors

are allocated than needed,

b) possible memory corruption, because further cyclic buffers were out

of the original buffers, due to the offset.

This patch fixes this problem by making the legacy S3C-DMA API use the same semantics as DMA engine (the whole cyclic buffer is enqueued at once) and modifying users of Samsung DMA wrappers in cyclic mode to behave appropriately.

Quoted 8 lines
Quoted 2 lines

If patch 1 thru 9 are uncontroversial now, maybe Vinod can apply these for v3.12 so we can get less noise and risk of collissions in the next merge window?

Just an idea.

That would be nice, leaving only Samsung-specific patches for the next merge window.

(That would be patches 1 to 8, though, as 9 is a patch for ASoC that could be picked up by Mark Brown independently.)

Best regards,
Tomasz

maintainer
#14 lore raw

Re: [PATCH 09/18] ASoC: Samsung: Do not queue cyclic buffers multiple times

In reply to Linus Walleij
Quoted 3 lines · Linus Walleij

If patch 1 thru 9 are uncontroversial now, maybe Vinod can apply these for v3.12 so we can get less noise and risk of collissions in the next merge window?

Patch 9 I was going to apply to ASoC towards the end of the release cycle - it shouldn't depend on the earlier ones as ASoC isn't using dmaengine yet. Holding off partly to run testing and partly in case this ends up getting applied.

maintainer
#15 lore raw

Re: [alsa-devel] [PATCH 09/18] ASoC: Samsung: Do not queue cyclic buffers multiple times

In reply to Tomasz Figa
Quoted 4 lines · Tomasz Figa

The legacy S3C-DMA API required every period of a cyclic buffer to be queued separately. After conversion of Samsung ASoC to Samsung DMA wrappers somebody made an assumption that the same is needed for DMA engine API, which is not true.

Applied, thanks.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130829/fc388564/attachment.sig>

#16 lore raw

Re: [alsa-devel] [PATCH 09/18] ASoC: Samsung: Do not queue cyclic buffers multiple times

Quoted 7 lines · Mark Brown
Quoted 4 lines · Tomasz Figa

The legacy S3C-DMA API required every period of a cyclic buffer to be queued separately. After conversion of Samsung ASoC to Samsung DMA wrappers somebody made an assumption that the same is needed for DMA engine API, which is not true.

Applied, thanks.

OK Vinod can you take in patch 1 thru 8?

Yours,
Linus Walleij

#17 lore raw

PATCH 10/18 spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

In reply to Tomasz Figa

With support for amba-pl08x driver, on S3C64xx the generic DMA engine API can be used instead of the private s3c-dma interface.

---
 drivers/spi/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/Kconfig +1 -1
index 89cbbab..241a049 100644
@@ -366,7 +366,7 @@ config SPI_S3C24XX_FIQ
 config SPI_S3C64XX
 	tristate "Samsung S3C64XX series type SPI"
 	depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
-	select S3C64XX_DMA if ARCH_S3C64XX
+	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
 	help
 	  SPI driver for Samsung S3C64XX and newer SoCs.
 
Signature · 1 line
1.8.3.2
maintainer
#18 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 2 lines · Tomasz Figa

With support for amba-pl08x driver, on S3C64xx the generic DMA engine API can be used instead of the private s3c-dma interface.

I'm still getting issues for SPI with this:

[   50.952845] s3c64xx-spi s3c6410-spi.0: Failed to get RX DMA channel
[   50.953520] spi_master spi0: failed to prepare transfer hardware

when I test (with -next with this series applied on top), this is from the first transfer that tries to DMA - there's actually no RX data. No errors are reported by the DMA controller itself. I'm also getting crashes setting up the audio DMA while derferencecing the channel.

This is without DT - are there any hookups missing because of that?

#19 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 9 lines · On Tuesday 13 of August 2013 00:36:41 Mark Brown wrote:
Quoted 2 lines · Tomasz Figa

With support for amba-pl08x driver, on S3C64xx the generic DMA engine API can be used instead of the private s3c-dma interface.

I'm still getting issues for SPI with this:

[   50.952845] s3c64xx-spi s3c6410-spi.0: Failed to get RX DMA channel
[   50.953520] spi_master spi0: failed to prepare transfer hardware
Quoted 6 lines

when I test (with -next with this series applied on top), this is from the first transfer that tries to DMA - there's actually no RX data. No errors are reported by the DMA controller itself. I'm also getting crashes setting up the audio DMA while derferencecing the channel.

This is without DT - are there any hookups missing because of that?

Hmm, strange.

I've been testing this without any significant patches, like PWM, CCF or DT support, just everything from the branch I pointed to and some board- specific patches to help in debugging.

Anyway, this is the exact branch I've been using:

git://github.com/tom3q/linux.git v3.12-pl080-devel

Best regards,
Tomasz

maintainer
#20 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 3 lines · Tomasz Figa

I've been testing this without any significant patches, like PWM, CCF or DT support, just everything from the branch I pointed to and some board- specific patches to help in debugging.

I retested with the SPI patches you sent separately yesterday which didn't make a difference for the SPI issue.

Quoted 3 lines

Anyway, this is the exact branch I've been using:

git://github.com/tom3q/linux.git v3.12-pl080-devel

I can't test this directly as it has the DAPM bugs I fixed yesterday
in it (those patches will hit -next tomorrow), however it does look like
there's nothing else relevant in there...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130813/d728e4e8/attachment.sig>

maintainer
#21 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

In reply to Tomasz Figa
Quoted 3 lines · Tomasz Figa

I've been testing this without any significant patches, like PWM, CCF or DT support, just everything from the branch I pointed to and some board- specific patches to help in debugging.

Done some more digging. It's not failing the first time it requests the channel, it's failing sometime later on (after we've been running for a while but when we've had a substantial idle period). However it is the first time we're actually intending to use the channel, previously to this the transfers would always be too small to trigger DMA. I'm not sure that's relevant though as we're not getting far enough to actually request the channel.

I'm still debugging what's going on here - the basic refcounting all looks OK in the SPI driver, I can see it requesting and releasing with the refcounts all going back to zero in the DMA driver as expected but when we come back to the device later on dmaengine is deciding the device is unavailable quite early on in the process.

maintainer Tested-by
#22 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 5 lines · Mark Brown

I'm still debugging what's going on here - the basic refcounting all looks OK in the SPI driver, I can see it requesting and releasing with the refcounts all going back to zero in the DMA driver as expected but when we come back to the device later on dmaengine is deciding the device is unavailable quite early on in the process.

The failure is happening because this check is failing:

	/* devices with multiple channels need special handling as we need to
	 * ensure that all channels are either private or public.
	 */
	if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask))
		list_for_each_entry(chan, &dev->channels, device_node) {
			/* some channels are already publicly allocated */
			if (chan->client_count) {

which is happening because dma1chan0 (which is on the same DMA controller as the SPI controller) and in fact every other DMA channel had references grabbed by the network stack dmaengine helpers which I'd enabled in config. The fact that they do that is unhelpful, it renders the API mostly useless, but is nothing to do with this series.

Having tweaked the config everything appears to work so:

though the whole thing with the filter function is as I say a bit fun from a code review point of view.

#23 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 10 lines · On Tuesday 13 of August 2013 21:18:16 Mark Brown wrote:
Quoted 5 lines · Mark Brown

I'm still debugging what's going on here - the basic refcounting all looks OK in the SPI driver, I can see it requesting and releasing with the refcounts all going back to zero in the DMA driver as expected but when we come back to the device later on dmaengine is deciding the device is unavailable quite early on in the process.

The failure is happening because this check is failing:

	/* devices with multiple channels need special handling as we need 

to

Quoted 13 lines
	 * ensure that all channels are either private or public.
	 */
	if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask))
		list_for_each_entry(chan, &dev->channels, device_node) {
			/* some channels are already publicly allocated */
			if (chan->client_count) {

which is happening because dma1chan0 (which is on the same DMA controller as the SPI controller) and in fact every other DMA channel had references grabbed by the network stack dmaengine helpers which I'd enabled in config. The fact that they do that is unhelpful, it renders the API mostly useless, but is nothing to do with this series.

Quoted 6 lines

Having tweaked the config everything appears to work so:

though the whole thing with the filter function is as I say a bit fun from a code review point of view.

I believe you just found another brokenness of current DMA channel matching.

Thanks for testing.

Best regards,
Tomasz

maintainer
#24 lore raw

Re: [PATCH 10/18] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX

Quoted 7 lines · Tomasz Figa
Quoted 4 lines · On Tuesday 13 of August 2013 21:18:16 Mark Brown wrote:
	if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask))
		list_for_each_entry(chan, &dev->channels, device_node) {
			/* some channels are already publicly allocated */
			if (chan->client_count) {
Quoted 8 lines
Quoted 5 lines

which is happening because dma1chan0 (which is on the same DMA controller as the SPI controller) and in fact every other DMA channel had references grabbed by the network stack dmaengine helpers which I'd enabled in config. The fact that they do that is unhelpful, it renders the API mostly useless, but is nothing to do with this series.

I believe you just found another brokenness of current DMA channel matching.

Yeah, at first glance the reference grabbing thing seems a bit peculiar.
I didn't research why it's done that way yet.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130813/42e6f326/attachment.sig>

#25 lore raw

PATCH 11/18 ASoC: Samsung: Do not require legacy DMA API in case of S3C64XX

In reply to Tomasz Figa

With support for amba-pl08x driver, on S3C64xx the generic DMA engine API can be used instead of the private s3c-dma interface.

---
 sound/soc/samsung/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/samsung/Kconfig +1 -1
index 9855dfc..55b514d 100644
@@ -1,7 +1,7 @@
 config SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
 	depends on PLAT_SAMSUNG
-	select S3C64XX_DMA if ARCH_S3C64XX
+	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
 	select S3C2410_DMA if ARCH_S3C24XX
 	help
 	  Say Y or M if you want to add support for codecs attached to
Signature · 1 line
1.8.3.2
#26 lore raw

PATCH 12/18 ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

In reply to Tomasz Figa

This patch adds all required platform-specific data and initialization code to support the generic amba-pl08x driver on S3C64xx SoCs.

Also some compatibility definitions are added to make the transition from legacy API to DMA engine easier. The biggest hack here is passing const char * pointers through DMA resource, casted to unsigned long, but this is how Samsung DMA wrappers (used to support both s3c-dma and DMA engine in drivers) are designed.

---
 arch/arm/Kconfig                         |   1 +
 arch/arm/mach-s3c64xx/Kconfig            |   8 +-
 arch/arm/mach-s3c64xx/Makefile           |   1 +
 arch/arm/mach-s3c64xx/common.h           |   5 +
 arch/arm/mach-s3c64xx/include/mach/dma.h |  65 ++++++++
 arch/arm/mach-s3c64xx/pl080.c            | 244 +++++++++++++++++++++++++++++++
 arch/arm/plat-samsung/devs.c             |   6 +-
 7 files changed, 326 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-s3c64xx/pl080.c
arch/arm/Kconfig +1 -0
index 43594d5..7e0e1b6 100644
@@ -721,6 +721,7 @@ config ARCH_S3C64XX
 	bool "Samsung S3C64XX"
 	select ARCH_HAS_CPUFREQ
 	select ARCH_REQUIRE_GPIOLIB
+	select ARM_AMBA
 	select ARM_VIC
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
arch/arm/mach-s3c64xx/Kconfig +7 -1
index 2057853..704c5e4 100644
@@ -28,9 +28,15 @@ config CPU_S3C6410
 	help
 	  Enable S3C6410 CPU support
 
+config S3C64XX_PL080
+	bool "S3C64XX DMA using generic PL08x driver"
+	select AMBA_PL08X
+	select SAMSUNG_DMADEV
+
 config S3C64XX_DMA
-	bool "S3C64XX DMA"
+	bool "S3C64XX DMA using legacy S3C DMA API"
 	select S3C_DMA
+	depends on !S3C64XX_PL080
 
 config S3C64XX_SETUP_SDHCI
 	bool
arch/arm/mach-s3c64xx/Makefile +1 -0
index 31d0c91..4e3326a 100644
@@ -27,6 +27,7 @@ obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 # DMA support
 
 obj-$(CONFIG_S3C64XX_DMA)	+= dma.o
+obj-$(CONFIG_S3C64XX_PL080)	+= pl080.o
 
 # Device support
 
arch/arm/mach-s3c64xx/common.h +5 -0
index e8f990b..4e84617 100644
@@ -60,4 +60,9 @@ int __init s3c64xx_pm_late_initcall(void);
 static inline int s3c64xx_pm_late_initcall(void) { return 0; }
 #endif
 
+#ifdef CONFIG_S3C64XX_PL080
+extern struct pl08x_platform_data s3c64xx_dma0_plat_data;
+extern struct pl08x_platform_data s3c64xx_dma1_plat_data;
+#endif
+
 #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */
arch/arm/mach-s3c64xx/include/mach/dma.h +65 -0

75 lines not on this page · raw message

arch/arm/mach-s3c64xx/pl080.c new file +244 -0

244 lines not on this page · raw message

arch/arm/plat-samsung/devs.c +3 -3
index 0f9c3f4..8509702 100644
@@ -1513,7 +1513,7 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA) || defined(CONFIG_S3C64XX_PL080)
 	pd.filter = pl330_filter;
 #endif
 
@@ -1554,7 +1554,7 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA) || defined(CONFIG_S3C64XX_PL080)
 	pd.filter = pl330_filter;
 #endif
 
@@ -1595,7 +1595,7 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA) || defined(CONFIG_S3C64XX_PL080)
 	pd.filter = pl330_filter;
 #endif
 
Signature · 1 line
1.8.3.2
maintainer
#27 lore raw

Re: [PATCH 12/18] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

Quoted 1 line · Tomasz Figa

+#define pl330_filter pl08x_filter_id

So, this is pretty fun and probably not going to play too nicely for multiplatform kernels...

#28 lore raw

Re: [PATCH 12/18] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

Quoted 5 lines · On Tuesday 13 of August 2013 18:52:51 Mark Brown wrote:
Quoted 1 line · Tomasz Figa

+#define pl330_filter pl08x_filter_id

So, this is pretty fun and probably not going to play too nicely for multiplatform kernels...

Yes, this is really funny and only shows the brokenness of current channel filtering mechanism used in DMA engine subsystem. Fortunately this is quite irrelevant to multiplatform kernels, because no users of it will be compiled in, since it's used only for legacy (non-DT) channel filtering.

Anyway, I would happily redesign and rewrite the DMA engine channel matching completely to make it much more sane, but I guess I would need an ack from Vinod and Dan to do it.

Best regards,
Tomasz

maintainer
#29 lore raw

Re: [PATCH 12/18] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

Quoted 5 lines · Tomasz Figa
Quoted 2 lines · On Tuesday 13 of August 2013 18:52:51 Mark Brown wrote:
Quoted 1 line · Tomasz Figa

+#define pl330_filter pl08x_filter_id

Quoted 7 lines
Quoted 2 lines

So, this is pretty fun and probably not going to play too nicely for multiplatform kernels...

Yes, this is really funny and only shows the brokenness of current channel filtering mechanism used in DMA engine subsystem. Fortunately this is quite irrelevant to multiplatform kernels, because no users of it will be compiled in, since it's used only for legacy (non-DT) channel filtering.

Well, the thing here is more about the fact that the match function is silently being hijacked - it should be possible to do this in the device registrations. I'd expect you could get a non-DT kernel which was affected, but you'd probably have to try.

Quoted 3 lines

Anyway, I would happily redesign and rewrite the DMA engine channel matching completely to make it much more sane, but I guess I would need an ack from Vinod and Dan to do it.

I'd be really keen to get this code merged sooner rather than later for
ASoC development so if there's a way to do it separately to fixing the
filtering that'd be good.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130813/4120754f/attachment.sig>

#30 lore raw

Re: [PATCH 12/18] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

Quoted 13 lines · On Tuesday 13 of August 2013 21:35:36 Mark Brown wrote:
Quoted 4 lines · Tomasz Figa
Quoted 3 lines · On Tuesday 13 of August 2013 18:52:51 Mark Brown wrote:
Quoted 1 line · Tomasz Figa

+#define pl330_filter pl08x_filter_id

Quoted 8 lines
Quoted 2 lines

So, this is pretty fun and probably not going to play too nicely for multiplatform kernels...

Yes, this is really funny and only shows the brokenness of current channel filtering mechanism used in DMA engine subsystem. Fortunately this is quite irrelevant to multiplatform kernels, because no users of it will be compiled in, since it's used only for legacy (non-DT) channel filtering.

Quoted 4 lines

Well, the thing here is more about the fact that the match function is silently being hijacked - it should be possible to do this in the device registrations. I'd expect you could get a non-DT kernel which was affected, but you'd probably have to try.

Let me see what I can do to improve things for now.

Quoted 7 lines
Quoted 3 lines

Anyway, I would happily redesign and rewrite the DMA engine channel matching completely to make it much more sane, but I guess I would need an ack from Vinod and Dan to do it.

I'd be really keen to get this code merged sooner rather than later for ASoC development so if there's a way to do it separately to fixing the filtering that'd be good.

I fully agree on this. I still have other things to work on, so the possible redesign of channel filtering would not probably happen before 3.12 merge window closes.

Best regards,
Tomasz

#31 lore raw

PATCH v2 12/18 ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver

In reply to Tomasz Figa

This patch adds all required platform-specific data and initialization code to support the generic amba-pl08x driver on S3C64xx SoCs.

Also some compatibility definitions are added to make the transition from legacy API to DMA engine easier. The biggest hack here is passing const char * pointers through DMA resource, casted to unsigned long, but this is how Samsung DMA wrappers (used to support both s3c-dma and DMA engine in drivers) are designed.

---
 arch/arm/Kconfig                         |   1 +
 arch/arm/mach-s3c64xx/Kconfig            |   8 +-
 arch/arm/mach-s3c64xx/Makefile           |   1 +
 arch/arm/mach-s3c64xx/common.h           |   5 +
 arch/arm/mach-s3c64xx/include/mach/dma.h |  63 ++++++++
 arch/arm/mach-s3c64xx/pl080.c            | 244 +++++++++++++++++++++++++++++++
 arch/arm/plat-samsung/devs.c             |  12 +-
 arch/arm/plat-samsung/dma-ops.c          |   8 +-
 8 files changed, 337 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-s3c64xx/pl080.c

Changes since v1:
- Stopped hijacking pl330_filter() symbol to plug pl08_filter_id() as channel filtering callback on S3C64xx.

arch/arm/Kconfig +1 -0
index 43594d5..7e0e1b6 100644
@@ -721,6 +721,7 @@ config ARCH_S3C64XX
 	bool "Samsung S3C64XX"
 	select ARCH_HAS_CPUFREQ
 	select ARCH_REQUIRE_GPIOLIB
+	select ARM_AMBA
 	select ARM_VIC
 	select CLKDEV_LOOKUP
 	select CLKSRC_MMIO
arch/arm/mach-s3c64xx/Kconfig +7 -1
index 2057853..704c5e4 100644
@@ -28,9 +28,15 @@ config CPU_S3C6410
 	help
 	  Enable S3C6410 CPU support
 
+config S3C64XX_PL080
+	bool "S3C64XX DMA using generic PL08x driver"
+	select AMBA_PL08X
+	select SAMSUNG_DMADEV
+
 config S3C64XX_DMA
-	bool "S3C64XX DMA"
+	bool "S3C64XX DMA using legacy S3C DMA API"
 	select S3C_DMA
+	depends on !S3C64XX_PL080
 
 config S3C64XX_SETUP_SDHCI
 	bool
arch/arm/mach-s3c64xx/Makefile +1 -0
index 31d0c91..4e3326a 100644
@@ -27,6 +27,7 @@ obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 # DMA support
 
 obj-$(CONFIG_S3C64XX_DMA)	+= dma.o
+obj-$(CONFIG_S3C64XX_PL080)	+= pl080.o
 
 # Device support
 
arch/arm/mach-s3c64xx/common.h +5 -0
index e8f990b..4e84617 100644
@@ -60,4 +60,9 @@ int __init s3c64xx_pm_late_initcall(void);
 static inline int s3c64xx_pm_late_initcall(void) { return 0; }
 #endif
 
+#ifdef CONFIG_S3C64XX_PL080
+extern struct pl08x_platform_data s3c64xx_dma0_plat_data;
+extern struct pl08x_platform_data s3c64xx_dma1_plat_data;
+#endif
+
 #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */
arch/arm/mach-s3c64xx/include/mach/dma.h +63 -0

73 lines not on this page · raw message

arch/arm/mach-s3c64xx/pl080.c new file +244 -0

244 lines not on this page · raw message

arch/arm/plat-samsung/devs.c +9 -3
index 0f9c3f4..90b4b61 100644
@@ -1513,8 +1513,10 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #endif
 
 	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0);
@@ -1554,8 +1556,10 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #endif
 
 	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
@@ -1595,8 +1599,10 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
 	pd.num_cs = num_cs;
 	pd.src_clk_nr = src_clk_nr;
 	pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
-#ifdef CONFIG_PL330_DMA
+#if defined(CONFIG_PL330_DMA)
 	pd.filter = pl330_filter;
+#elif defined(CONFIG_S3C64XX_PL080)
+	pd.filter = pl08x_filter_id;
 #endif
 
 	s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
arch/arm/plat-samsung/dma-ops.c +7 -1
index ec0d731..886326e 100644
@@ -18,6 +18,12 @@
 
 #include <mach/dma.h>
 
+#if defined(CONFIG_PL330_DMA)
+#define dma_filter pl330_filter
+#elif defined(CONFIG_S3C64XX_PL080)
+#define dma_filter pl08x_filter_id
+#endif
+
 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 				struct samsung_dma_req *param,
 				struct device *dev, char *ch_name)
@@ -30,7 +36,7 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 	if (dev->of_node)
 		return (unsigned)dma_request_slave_channel(dev, ch_name);
 	else
-		return (unsigned)dma_request_channel(mask, pl330_filter,
+		return (unsigned)dma_request_channel(mask, dma_filter,
 							(void *)dma_ch);
 }
 
Signature · 1 line
1.8.3.2
#32 lore raw

PATCH 13/18 ARM: s3c64xx: clock: Add clkdev lookup for DMA clocks

In reply to Tomasz Figa

This patch adds clkdev lookup entries for clocks used by PL08x DMA driver.

---
 arch/arm/mach-s3c64xx/clock.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)
arch/arm/mach-s3c64xx/clock.c +18 -10
index 8499415..33aa851 100644
@@ -194,16 +194,6 @@ static struct clk init_clocks_off[] = {
 		.enable		= s3c64xx_hclk_ctrl,
 		.ctrlbit	= S3C_CLKCON_HCLK_IHOST,
 	}, {
-		.name		= "dma0",
-		.parent		= &clk_h,
-		.enable		= s3c64xx_hclk_ctrl,
-		.ctrlbit	= S3C_CLKCON_HCLK_DMA0,
-	}, {
-		.name		= "dma1",
-		.parent		= &clk_h,
-		.enable		= s3c64xx_hclk_ctrl,
-		.ctrlbit	= S3C_CLKCON_HCLK_DMA1,
-	}, {
 		.name		= "3dse",
 		.parent		= &clk_h,
 		.enable		= s3c64xx_hclk_ctrl,
@@ -345,6 +335,20 @@ static struct clk clk_i2s2 = {
 };
 #endif
 
+static struct clk clk_dma0 = {
+	.name		= "dma0",
+	.parent		= &clk_h,
+	.enable		= s3c64xx_hclk_ctrl,
+	.ctrlbit	= S3C_CLKCON_HCLK_DMA0,
+};
+
+static struct clk clk_dma1 = {
+	.name		= "dma1",
+	.parent		= &clk_h,
+	.enable		= s3c64xx_hclk_ctrl,
+	.ctrlbit	= S3C_CLKCON_HCLK_DMA1,
+};
+
 static struct clk init_clocks[] = {
 	{
 		.name		= "lcd",
@@ -849,6 +853,8 @@ static struct clk *clk_cdev[] = {
 	&clk_48m_spi1,
 	&clk_i2s0,
 	&clk_i2s1,
+	&clk_dma0,
+	&clk_dma1,
 };
 
 static struct clk_lookup s3c64xx_clk_lookup[] = {
@@ -873,6 +879,8 @@ static struct clk_lookup s3c64xx_clk_lookup[] = {
 	CLKDEV_INIT("samsung-i2s.2", "i2s_opclk0", &clk_i2s2),
 	CLKDEV_INIT("samsung-i2s.2", "i2s_opclk1", &clk_audio_bus2.clk),
 #endif
+	CLKDEV_INIT("dma-pl080s.0", "apb_pclk", &clk_dma0),
+	CLKDEV_INIT("dma-pl080s.1", "apb_pclk", &clk_dma1),
 };
 
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
Signature · 1 line
1.8.3.2
#33 lore raw

PATCH 14/18 clk: samsung: s3c64xx: Add aliases for DMA clocks

In reply to Tomasz Figa

This patch adds clkdev aliases for clocks used by PL08x DMA driver.

---
 drivers/clk/samsung/clk-s3c64xx.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/clk/samsung/clk-s3c64xx.c +2 -0
index eeda567..79ee9a6 100644
@@ -332,7 +332,9 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
 	ALIAS(HCLK_DMA1, NULL, "dma1"),
+	ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
 	ALIAS(HCLK_DMA0, NULL, "dma0"),
+	ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
 	ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
 	ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
 	ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),
Signature · 1 line
1.8.3.2
Acked-by on v1 14/18
#34 lore raw

Re: [PATCH 14/18] clk: samsung: s3c64xx: Add aliases for DMA clocks

Quoting Tomasz Figa (2013-08-11 10:59:26)

Quoted 3 lines

This patch adds clkdev aliases for clocks used by PL08x DMA driver.

Quoted 20 lines
---
 drivers/clk/samsung/clk-s3c64xx.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/clk/samsung/clk-s3c64xx.c +2 -0
index eeda567..79ee9a6 100644
@@ -332,7 +332,9 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
        ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
        ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
        ALIAS(HCLK_DMA1, NULL, "dma1"),
+       ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
        ALIAS(HCLK_DMA0, NULL, "dma0"),
+       ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
        ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
        ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
        ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),
Signature · 1 line
1.8.3.2
#35 lore raw

PATCH 15/18 ARM: s3c64xx: Remove legacy DMA driver

In reply to Tomasz Figa

Since support for generic PL08x DMA engine driver has been added, there is no need to keep the old legacy driver, so this patch removes it.

---
 arch/arm/mach-s3c64xx/Kconfig            |   5 -
 arch/arm/mach-s3c64xx/Makefile           |   1 -
 arch/arm/mach-s3c64xx/dma.c              | 753 -------------------------------
 arch/arm/mach-s3c64xx/include/mach/dma.h | 123 -----
 4 files changed, 882 deletions(-)
 delete mode 100644 arch/arm/mach-s3c64xx/dma.c
arch/arm/mach-s3c64xx/Kconfig +0 -5
index 704c5e4..940dd7f 100644
@@ -33,11 +33,6 @@ config S3C64XX_PL080
 	select AMBA_PL08X
 	select SAMSUNG_DMADEV
 
-config S3C64XX_DMA
-	bool "S3C64XX DMA using legacy S3C DMA API"
-	select S3C_DMA
-	depends on !S3C64XX_PL080
-
 config S3C64XX_SETUP_SDHCI
 	bool
 	select S3C64XX_SETUP_SDHCI_GPIO
arch/arm/mach-s3c64xx/Makefile +0 -1
index 4e3326a..5607547 100644
@@ -26,7 +26,6 @@ obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o
 
 # DMA support
 
-obj-$(CONFIG_S3C64XX_DMA)	+= dma.o
 obj-$(CONFIG_S3C64XX_PL080)	+= pl080.o
 
 # Device support
arch/arm/mach-s3c64xx/dma.c deleted +0 -753

753 lines not on this page · raw message

arch/arm/mach-s3c64xx/include/mach/dma.h +0 -123

133 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#36 lore raw

PATCH 16/18 clk: samsung: s3c64xx: Remove clock aliases of old DMA driver

In reply to Tomasz Figa

Since the old DMA driver got removed, these aliases are no longer necessary.

---
 drivers/clk/samsung/clk-s3c64xx.c | 2 --
 1 file changed, 2 deletions(-)
drivers/clk/samsung/clk-s3c64xx.c +0 -2
index 79ee9a6..dd47a83 100644
@@ -331,9 +331,7 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
 	ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
 	ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
-	ALIAS(HCLK_DMA1, NULL, "dma1"),
 	ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
-	ALIAS(HCLK_DMA0, NULL, "dma0"),
 	ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
 	ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
 	ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
Signature · 1 line
1.8.3.2
Acked-by on v1 16/18
#37 lore raw

Re: [PATCH 16/18] clk: samsung: s3c64xx: Remove clock aliases of old DMA driver

Quoting Tomasz Figa (2013-08-11 10:59:28)

Quoted 4 lines

Since the old DMA driver got removed, these aliases are no longer necessary.

Quoted 20 lines
---
 drivers/clk/samsung/clk-s3c64xx.c | 2 --
 1 file changed, 2 deletions(-)
drivers/clk/samsung/clk-s3c64xx.c +0 -2
index 79ee9a6..dd47a83 100644
@@ -331,9 +331,7 @@ static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
        ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
        ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
        ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
-       ALIAS(HCLK_DMA1, NULL, "dma1"),
        ALIAS(HCLK_DMA1, "dma-pl080s.1", "apb_pclk"),
-       ALIAS(HCLK_DMA0, NULL, "dma0"),
        ALIAS(HCLK_DMA0, "dma-pl080s.0", "apb_pclk"),
        ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
        ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
Signature · 1 line
1.8.3.2
#38 lore raw

PATCH 17/18 spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

In reply to Tomasz Figa

The legacy S3C64xx DMA driver has been removed, DMA support on S3C64xx is provided only by the generic PL08x driver.

This patch modifies the Kconfig entry of spi-s3c64xx driver, which relies on availability of DMA, to always select the S3C64XX_PL080 symbol.

---
 drivers/spi/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/Kconfig +1 -1
index 241a049..a13867e 100644
@@ -366,7 +366,7 @@ config SPI_S3C24XX_FIQ
 config SPI_S3C64XX
 	tristate "Samsung S3C64XX series type SPI"
 	depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
-	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
+	select S3C64XX_PL080 if ARCH_S3C64XX
 	help
 	  SPI driver for Samsung S3C64XX and newer SoCs.
 
Signature · 1 line
1.8.3.2
maintainer
#39 lore raw

Re: [PATCH 17/18] spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

drivers/spi/Kconfig config SPI_S3C24XX_FIQ · line 371

Quoted 8 lines · Tomasz Figa
drivers/spi/Kconfig +1 -1
@@ -366,7 +366,7 @@ config SPI_S3C24XX_FIQ
 config SPI_S3C64XX
 	tristate "Samsung S3C64XX series type SPI"
 	depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
-	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
+	select S3C64XX_PL080 if ARCH_S3C64XX
 	help
 	  SPI driver for Samsung S3C64XX and newer SoCs.

Do we need the select here (or should we have other selects for the
Exynos SoCs)?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130811/e4eca38b/attachment.sig>

#40 lore raw

Re: [PATCH 17/18] spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

Hi Mark,

Quoted 11 lines · On Sunday 11 of August 2013 20:11:40 Mark Brown wrote:
Quoted 10 lines · Tomasz Figa
drivers/spi/Kconfig +1 -1
@@ -366,7 +366,7 @@ config SPI_S3C24XX_FIQ
 
 config SPI_S3C64XX
 
 	tristate "Samsung S3C64XX series type SPI"
 	depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 ||
 	ARCH_EXYNOS)> 
-	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
+	select S3C64XX_PL080 if ARCH_S3C64XX
Quoted 6 lines

drivers/spi/Kconfig config SPI_S3C24XX_FIQ · line 371

Quoted 3 lines
drivers/spi/Kconfig +0 -0
 	help
 
 	  SPI driver for Samsung S3C64XX and newer SoCs.

Do we need the select here (or should we have other selects for the Exynos SoCs)?

The driver would build fine without this symbol selected, but since it relies on availability of DMA, it doesn't make too much sense to build it this way. This kind of selects makes kernel configuration more user friendly IMHO.

Possibly adding appropriate selects (PL330) for s5p* and exynos could make sense.

Best regards,
Tomasz

maintainer
#41 lore raw

Re: [PATCH 17/18] spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

Quoted 5 lines · Tomasz Figa
Quoted 2 lines · On Sunday 11 of August 2013 20:11:40 Mark Brown wrote:

Do we need the select here (or should we have other selects for the Exynos SoCs)?

Quoted 7 lines

The driver would build fine without this symbol selected, but since it relies on availability of DMA, it doesn't make too much sense to build it this way. This kind of selects makes kernel configuration more user friendly IMHO.

Possibly adding appropriate selects (PL330) for s5p* and exynos could make sense.

Right. On these SoCs it's probably worth doing it in the arch/arm code
rather than for every device using the controller though, it's the same
DMA controller for everything.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130812/881733fb/attachment.sig>

#42 lore raw

PATCH 18/18 ASoC: Samsung: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

In reply to Tomasz Figa

The legacy S3C64xx DMA driver has been removed, DMA support on S3C64xx is provided only by the generic PL08x driver.

This patch modifies the Kconfig entry of Samsung ASoC subsystem, which relies on availability of DMA, to always select the S3C64XX_PL080 symbol.

---
 sound/soc/samsung/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/samsung/Kconfig +1 -1
index 55b514d..5b5be90 100644
@@ -1,7 +1,7 @@
 config SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
 	depends on PLAT_SAMSUNG
-	select S3C64XX_DMA if ARCH_S3C64XX && !S3C64XX_PL080
+	select S3C64XX_PL080 if ARCH_S3C64XX
 	select S3C2410_DMA if ARCH_S3C24XX
 	help
 	  Say Y or M if you want to add support for codecs attached to
Signature · 1 line
1.8.3.2
#43 lore raw
In reply to Tomasz Figa

Hi,

[Ccing maintainers and other people responsible for spear, lpc32xx and versatile platforms]

Quoted 28 lines · On Sunday 11 of August 2013 19:59:12 Tomasz Figa wrote:

This is first non-RFC version of my patches extending support of amba-pl08x DMA engine driver to PL080S DMA engine (PL080 modified by Samsung) found in Samsung S3C64xx SoCs.

Due to changes scattered across different areas of kernel, patches are based on merged 3 branches:
- for-next of Kgene's Samsung tree,
- clk-next of Mike's clock tree,
- next of Vinod's slave DMA tree.

To ease testing I have prepared a branch in my private tree for anyone willing to check the patches out:

	git://github.com/tom3q/linux.git v3.12-pl080

Dependencies (already applied in my branch):
- for patches 14 and 16 - CCF-based clock driver for s3c64xx.

Some of the patches not related to the amba-pl08x driver itself can be likely applied into appropriate trees separately, namely:
- 09/18 - ASoC: Samsung: Do not queue cyclic buffers multiple times,
- 14/18 - clk: samsung: s3c64xx: Add aliases for DMA clocks.

After patch 14/18, both old and new DMA drivers can be supported on S3C64xx, depending on Kconfig options. Patches 15-18 remove the old driver leaving support only for the generic pl08x driver. Feel free to drop those patches for now if we want more testing, but I don't suspect any problems.

Quoted 5 lines

On S3C64xx-based Mini6410 and SMDK6410 boards, with I2S audio playback and capture (including full duplex operation) and also SPI using spidev:

It would be nice if patches from this series touching the PL08x driver (01-08) could be tested on other platforms that have this DMA controller as well, to make sure I did not break anything. Unfortunately I do not have any board based on any of them.

Best regards,
Tomasz

Quoted 116 lines

Changes since RFC v2:
- Added clkdev lookups to old clock driver.
- Added patches removing the old DMA driver and any remaining code needed by it.
- Fixed DMA support for SPI.
- Added a word about PL080S to amba-pl08x.c file header.
- Changed definition of LLI words from enums to macros.
- Extended debugging messages to handle PL080S variant as well.
- Little cleanup of LLI dumping code.
- Added check for peripheral flow control, which is unsupported by PL080S to dma_set_runtime_config.
- Corrected transfer size mask of PL080S.

Changes since RFC v1:
- Returned to original way of storing quirks as booleans, as suggested by Russell, Linus and Arnd.
- Added reg_config field to pl08x_phy_chan struct, which stores variant-specific address of channel config register, as suggested by Russell.
- Simplified handling of extended maximum transfer size of PL080S (no more conditional passing of 0 as length to pl08x_cctl_bits()).
- Reworked LLI handling in the driver to stop casting arbitrary memory to a struct and allow different word count of LLI entry, as suggested
by Linus.
- Removed AMBA ID override from S3C64xx PL080 initialization code.
- Fixed brokenness of Samsung DMA wrapper API, which caused cyclic
buffers to be queued multiple times when DMA engine is used.
- Included patch adding clock aliases for DMA engines (depends on Common Clock Framework driver for S3C64xx).
- Fixed several minor stylistic issues.

For reference, here is the original description of the series:

One of the biggest roadblocks on the way of S3C64xx to DeviceTree support is its DMA driver, which is completely platform-specific and provides private API (s3c-dma), not even saying that its design is completely against multiplatform-awareness.

The DMA controller present on this SoC series is a custom variant of ARM PrimeCell PL080 modified by Samsung to add some extra features. It is mostly compatible with original PL080, except:
- CH_CONTROL2 register is added between CH_CONTROL and CH_CONFIG,
- offset of CH_CONFIG register is different,
- transfer size field is moved from CH_CONTROL to CH_CONTROL2,
- transfer size field is extended to 24 bits, allowing much bigger single transfer,
- LLI consists of one more word, to account for CH_CONTROL2 register.

Since all the rest is fully compatible with standard PL080 there is no point in having separate driver just for this single variant, so I decided to look into adding support for it to the amba-pl08x driver.

There was already some attempt to achieve this before, but this was before Russel's big rework of the driver to use virtual channels, making the old patches being not much of use.

This RFC series is a proof of concept that I managed to make during last days of hacking. Except one patch adding clkdev lookup to clock driver (which is being replaced with a CCF-compliant driver ATM), this is enough to get memcpy and slave transfers to work on S3C64xx.

I have tested this on Mini6410 and SMDK6410 boards using dmatest for memcpy and Samsung I2S with madplay/aplay for slave transfers. Unfortunately I do not have access to other platforms with PL08x so I could not test for any regressions introduced on them.

Credits for two patches go to Alban Bedel, who made a series fixing this driver to make it usable with audio drivers. I rebased his patches on top of mine and corrected coding style a bit.

OK, that's all. Any comments are welcome. Feel free to start throwing eggs and tomatoes if you find this awful, but I won't be upset if I get some Tested-by or Acked-by as well. ;)

Alban Bedel (2):
dmaengine: PL08x: Fix reading the byte count in cctl
dmaengine: PL08x: Add cyclic transfer support

Tomasz Figa (16):
dmaengine: PL08x: Refactor pl08x_getbytes_chan() to lower indentation
dmaengine: PL08x: Add support for different offset of CONFIG register
dmaengine: PL08x: Rework LLI handling to be less fragile
dmaengine: PL08x: Move LLI dumping code into separate function
dmaengine: PL08x: Add support for PL080S variant
dmaengine: PL08x: Add support for different maximum transfer size
ASoC: Samsung: Do not queue cyclic buffers multiple times
spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX
ASoC: Samsung: Do not require legacy DMA API in case of S3C64XX
ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver
ARM: s3c64xx: clock: Add clkdev lookup for DMA clocks
clk: samsung: s3c64xx: Add aliases for DMA clocks
ARM: s3c64xx: Remove legacy DMA driver
clk: samsung: s3c64xx: Remove clock aliases of old DMA driver
spi: s3c64xx: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled
ASoC: Samsung: Always select S3C64XX_PL080 when ARCH_S3C64XX is enabled

 arch/arm/Kconfig                         |   1 +
 arch/arm/mach-s3c64xx/Kconfig            |   7 +-
 arch/arm/mach-s3c64xx/Makefile           |   2 +-
 arch/arm/mach-s3c64xx/clock.c            |  28 +-
 arch/arm/mach-s3c64xx/common.h           |   5 +
 arch/arm/mach-s3c64xx/dma.c              | 753
-------------------------------
arch/arm/mach-s3c64xx/include/mach/dma.h | 144 ++----
 arch/arm/mach-s3c64xx/pl080.c            | 244 ++++++++++
 arch/arm/plat-samsung/devs.c             |   6 +-
 arch/arm/plat-samsung/s3c-dma-ops.c      |  13 +-
 drivers/clk/samsung/clk-s3c64xx.c        |   4 +-
 drivers/dma/amba-pl08x.c                 | 501 ++++++++++++++------
 drivers/spi/Kconfig                      |   2 +-
 include/linux/amba/pl080.h               |   1 +
 sound/soc/samsung/Kconfig                |   2 +-
 sound/soc/samsung/dma.c                  |   7 +
 16 files changed, 705 insertions(+), 1015 deletions(-)
 delete mode 100644 arch/arm/mach-s3c64xx/dma.c
 create mode 100644 arch/arm/mach-s3c64xx/pl080.c
#44 lore raw
In reply to Tomasz Figa
Quoted 22 lines · Tomasz Figa

This is first non-RFC version of my patches extending support of amba-pl08x DMA engine driver to PL080S DMA engine (PL080 modified by Samsung) found in Samsung S3C64xx SoCs.

Due to changes scattered across different areas of kernel, patches are based on merged 3 branches:
- for-next of Kgene's Samsung tree,
- clk-next of Mike's clock tree,
- next of Vinod's slave DMA tree.

To ease testing I have prepared a branch in my private tree for anyone willing to check the patches out:

	git://github.com/tom3q/linux.git v3.12-pl080

Dependencies (already applied in my branch):
- for patches 14 and 16 - CCF-based clock driver for s3c64xx.

Some of the patches not related to the amba-pl08x driver itself can be likely applied into appropriate trees separately, namely:
- 09/18 - ASoC: Samsung: Do not queue cyclic buffers multiple times,
- 14/18 - clk: samsung: s3c64xx: Add aliases for DMA clocks.

Quoted 8 lines

After patch 14/18, both old and new DMA drivers can be supported on S3C64xx, depending on Kconfig options. Patches 15-18 remove the old driver leaving support only for the generic pl08x driver. Feel free to drop those patches for now if we want more testing, but I don't suspect any problems.

On S3C64xx-based Mini6410 and SMDK6410 boards, with I2S audio playback and capture (including full duplex operation) and also SPI using spidev:

Applied 1-8 to slave-dma tree, thanks

~Vinod