Skip to contentSkip to conversation

mmp audio support

PATCH Superseded Zhangfei Gao 4 participants 21 messages Jun 4, 2012 – Jun 8, 2012

Subsystems (4)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover mmp audio support

v0->v1:
dmaengine -> soc-dmaengine.
update according to Mark's suggestion

These patches provide mmp audio support under alsa via dmaengine Support platfrom pxa688 and pxa910
mmp_tdma.c and mmp-pcm.c is shared for pxa688 and pxa910 pxa688 (mmp2) use mmp2-sspa.c
pxa910 directly use pxa-ssp.c
mmp_tdma.c is under dmaengine framework

Verified on brownstone (pxa688) and ttc-dkb

Qiao Zhou (1):
ASoC: add ttc-dkb machine support

Zhangfei Gao (4):
dmaengine: mmp_tdma: add mmp tdma support
ASoC: mmp: add audio dma support
ASOC: mmp: add sspa support
ASoC: add mmp brownstone support

 drivers/dma/Kconfig                     |   10 +
 drivers/dma/Makefile                    |    1 +
 drivers/dma/mmp_tdma.c                  |  649 +++++++++++++++++++++++++++++++
 include/linux/platform_data/mmp_audio.h |   22 +
 include/linux/platform_data/mmp_dma.h   |   20 +
 sound/soc/pxa/Kconfig                   |   42 ++
 sound/soc/pxa/Makefile                  |    8 +
 sound/soc/pxa/brownstone.c              |  178 +++++++++
 sound/soc/pxa/mmp-pcm.c                 |  317 +++++++++++++++
 sound/soc/pxa/mmp-sspa.c                |  496 +++++++++++++++++++++++
 sound/soc/pxa/mmp-sspa.h                |   92 +++++
 sound/soc/pxa/ttc-dkb.c                 |  173 ++++++++
 12 files changed, 2008 insertions(+), 0 deletions(-)
 create mode 100644 drivers/dma/mmp_tdma.c
 create mode 100644 include/linux/platform_data/mmp_audio.h
 create mode 100644 include/linux/platform_data/mmp_dma.h
 create mode 100644 sound/soc/pxa/brownstone.c
 create mode 100644 sound/soc/pxa/mmp-pcm.c
 create mode 100644 sound/soc/pxa/mmp-sspa.c
 create mode 100644 sound/soc/pxa/mmp-sspa.h
 create mode 100644 sound/soc/pxa/ttc-dkb.c
#1 lore raw

PATCH 1/5 dmaengine: mmp_tdma: add mmp tdma support

Add support for two-channel dma under dmaengine
support: mmp-adma and pxa910-squ

---
 drivers/dma/Kconfig                   |   10 +
 drivers/dma/Makefile                  |    1 +
 drivers/dma/mmp_tdma.c                |  649 +++++++++++++++++++++++++++++++++
 include/linux/platform_data/mmp_dma.h |   20 +
 4 files changed, 680 insertions(+), 0 deletions(-)
 create mode 100644 drivers/dma/mmp_tdma.c
 create mode 100644 include/linux/platform_data/mmp_dma.h
drivers/dma/Kconfig +10 -0
index ef378b5..26d5b1b 100644
@@ -259,6 +259,16 @@ config DMA_SA11X0
 	  SA-1110 SoCs.  This DMA engine can only be used with on-chip
 	  devices.
 
+config MMP_TDMA
+	bool "MMP Two-Channel DMA support"
+	default ARCH_MMP
+	select DMA_ENGINE
+	help
+	  Support the MMP Two-Channel DMA engine.
+	  This engine used for MMP Audio DMA and pxa910 SQU.
+
+	  Say Y here if you enabled MMP ADMA, otherwise say N.
+
 config DMA_ENGINE
 	bool
 
drivers/dma/Makefile +1 -0
index 86b795b..37e9258 100644
@@ -28,3 +28,4 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
+obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
drivers/dma/mmp_tdma.c new file +649 -0

649 lines not on this page · raw message

include/linux/platform_data/mmp_dma.h new file +20 -0
new file mode 100644
index 0000000..4e21cf9
@@ -0,0 +1,20 @@
+/*
+ *  MMP Platform DMA Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_DMA_H
+#define MMP_DMA_H
+
+struct mmp_tdma_data {
+	u32 bus_size;
+	u32 pack_mod;
+};
+
+#endif /* MMP_DMA_H */
Signature · 1 line
1.7.1
#2 lore raw

Re: [PATCH v1 1/5] dmaengine: mmp_tdma: add mmp tdma support

Quoted 9 lines · Zhangfei Gao

Add support for two-channel dma under dmaengine
support: mmp-adma and pxa910-squ

drivers/dma/mmp_tdma.c new file +1 -0
+

drivers/dma/mmp_tdma.c line 259

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
+{
+	u32 reg = readl(tdmac->reg_base + TDISR);
+
+	if (reg & TDISR_COMP) {
+		/* clear irq */
+		reg &= ~TDISR_COMP;
+		writel(reg, tdmac->reg_base + TDISR);
+
+		return 1;

hrmm.?

Quoted 54 lines
drivers/dma/mmp_tdma.c new file +54 -0
+	}
+	return 0;
+}
+
+static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
+{
+	struct mmp_tdma_chan *tdmac = dev_id;
+
+	if (mmp_tdma_clear_chan_irq(tdmac)) {
+		tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
+		tasklet_schedule(&tdmac->tasklet);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+static irqreturn_t mmp_tdma_int_handler(int irq, void *dev_id)
+{
+	struct mmp_tdma_device *tdev = dev_id;
+	int i, ret;
+	int irq_num = 0;
+
+	for (i = 0; i < TDMA_CHANNEL_NUM; i++) {
+		struct mmp_tdma_chan *tdmac = tdev->tdmac[i];
+
+		ret = mmp_tdma_chan_handler(irq, tdmac);
+		if (ret == IRQ_HANDLED)
+			irq_num++;
+	}
+
+	if (irq_num)
+		return IRQ_HANDLED;
+	else
+		return IRQ_NONE;
+}
+
+static void dma_do_tasklet(unsigned long data)
+{
+	struct mmp_tdma_chan *tdmac = (struct mmp_tdma_chan *)data;
+
+	if (tdmac->desc.callback)
+		tdmac->desc.callback(tdmac->desc.callback_param);
+
+}
+
+static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
+{
+	struct gen_pool *gpool;
+	int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+	gpool = sram_get_gpool("asram");
+	if (tdmac->desc_arr)
+		gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
+				size);

drivers/dma/mmp_tdma.c line 323

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+	tdmac->desc_arr = NULL;
+
+	return;
+}
+
+static dma_cookie_t mmp_tdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(tx->chan);
+
+	mmp_tdma_chan_set_desc(tdmac, tdmac->desc_arr_phys);

This seems odd. In submit you are supposed to move this to your pending list. Btw where is the .issue_pending handler?

Quoted 12 lines
drivers/dma/mmp_tdma.c new file +12 -0
+
+	return 0;
+}
+
+static int mmp_tdma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	int ret;
+
+	dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+	dma_async_tx_descriptor_init(&tdmac->desc, chan);

drivers/dma/mmp_tdma.c line 345

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+	tdmac->desc.tx_submit = mmp_tdma_tx_submit;
+
+	if (tdmac->irq) {
+		ret = devm_request_irq(tdmac->dev, tdmac->irq,
+			mmp_tdma_chan_handler, IRQF_DISABLED, "tdma", tdmac);
+		if (ret)
+			goto err_request_irq;
+	}
+
+	return 0;

NO. This is supposed to return the number of descriptors allocated.

Quoted 5 lines
drivers/dma/mmp_tdma.c new file +5 -0
+
+err_request_irq:
+	mmp_tdma_free_descriptor(tdmac);
+	return ret;
+}

drivers/dma/mmp_tdma.c line 360

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+
+static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+	dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+	if (tdmac->irq)
+		devm_free_irq(tdmac->dev, tdmac->irq, tdmac);
+	mmp_tdma_disable_chan(tdmac);

channel should be already disabled, why do you need this here?

Quoted 8 lines
drivers/dma/mmp_tdma.c new file +8 -0
+	mmp_tdma_free_descriptor(tdmac);
+	return;
+}
+
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,

drivers/dma/mmp_tdma.c line 378

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+		unsigned long flags, void *context)
+{
+	/*
+	 * This operation is not supported on the TDMA controller
+	 *
+	 * However, we need to provide the function pointer to allow the
+	 * device_control() method to work.
+	 */
+	return NULL;
+}

Pls remove if not supported

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+
+static int mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+{
+	struct gen_pool *gpool;
+	int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+	dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)

drivers/dma/mmp_tdma.c line 398

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+		return -ENOMEM;
+
+	tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size);
+	if (!tdmac->desc_arr)
+		return -ENOMEM;
+
+	tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool,
+			(unsigned long)tdmac->desc_arr);
+
+	return 0;

this needs fix

Quoted 13 lines
drivers/dma/mmp_tdma.c new file +13 -0
+}
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_transfer_direction direction,
+		void *context)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	int num_periods = buf_len / period_len;
+	int i = 0, buf = 0;
+	int ret;
+
+	if (tdmac->status != DMA_SUCCESS)

drivers/dma/mmp_tdma.c line 421

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+		return NULL;
+
+	if (period_len > TDMA_MAX_XFER_BYTES) {
+		dev_err(tdmac->dev,
+				"maximum period size exceeded: %d > %d\n",
+				period_len, TDMA_MAX_XFER_BYTES);
+		goto err_out;
+	}
+
+	tdmac->status = DMA_IN_PROGRESS;

???

drivers/dma/mmp_tdma.c line 428

Quoted 7 lines
drivers/dma/mmp_tdma.c new file +7 -0
+	tdmac->desc_num = num_periods;
+	ret = mmp_tdma_alloc_descriptor(tdmac);
+	if (ret < 0)
+		goto err_out;
+
+	while (buf < buf_len) {
+		struct mmp_tdma_desc *desc = &tdmac->desc_arr[i];

what if i call prepare twice on the same channel?
Better way would to manage a descriptor list, see other drivers for examples.

drivers/dma/mmp_tdma.c line 434

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+		if (i + 1 == num_periods)
+			desc->nxt_desc = tdmac->desc_arr_phys;
+		else
+			desc->nxt_desc = tdmac->desc_arr_phys +
+				sizeof(*desc) * (i + 1);

pls use kernel link list, it is provided to you so that you dont have to do above.

Quoted 64 lines
drivers/dma/mmp_tdma.c new file +64 -0
+
+		if (direction == DMA_MEM_TO_DEV) {
+			desc->src_addr = dma_addr;
+			desc->dst_addr = tdmac->dev_addr;
+		} else {
+			desc->src_addr = tdmac->dev_addr;
+			desc->dst_addr = dma_addr;
+		}
+		desc->byte_cnt = period_len;
+		dma_addr += period_len;
+		buf += period_len;
+		i++;
+	}
+
+	tdmac->buf_len = buf_len;
+	tdmac->period_len = period_len;
+	tdmac->pos = 0;
+
+	return &tdmac->desc;
+
+err_out:
+	tdmac->status = DMA_ERROR;
+	return NULL;
+}
+
+static int mmp_tdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+	struct dma_slave_config *dmaengine_cfg = (void *)arg;
+	int ret = 0;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		mmp_tdma_disable_chan(tdmac);
+		break;
+	case DMA_PAUSE:
+		mmp_tdma_pause_chan(tdmac);
+		break;
+	case DMA_RESUME:
+		mmp_tdma_resume_chan(tdmac);
+		break;
+	case DMA_SLAVE_CONFIG:
+		if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+			tdmac->dev_addr = dmaengine_cfg->src_addr;
+			tdmac->burst_sz = dmaengine_cfg->src_maxburst;
+		} else {
+			tdmac->dev_addr = dmaengine_cfg->dst_addr;
+			tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
+		}
+		tdmac->dir = dmaengine_cfg->direction;
+		return mmp_tdma_config_chan(tdmac);
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
+			dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+

drivers/dma/mmp_tdma.c line 508

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+	dma_set_residue(txstate, tdmac->buf_len - tdmac->pos);
+
+	return tdmac->status;
+}
+
+static void mmp_tdma_issue_pending(struct dma_chan *chan)
+{
+	struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+	mmp_tdma_enable_chan(tdmac);

can you queue the descriptors here? That was purpose to have separate issue pending and submit.

Quoted 131 lines
drivers/dma/mmp_tdma.c new file +131 -0
+}
+
+static int __devexit mmp_tdma_remove(struct platform_device *pdev)
+{
+	struct mmp_tdma_device *tdev = platform_get_drvdata(pdev);
+
+	dma_async_device_unregister(&tdev->device);
+	return 0;
+}
+
+static int __devinit mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
+						int idx, int irq, int type)
+{
+	struct mmp_tdma_chan *tdmac;
+
+	if (idx >= TDMA_CHANNEL_NUM) {
+		dev_err(tdev->dev, "too many channels for device!\n");
+		return -EINVAL;
+	}
+
+	/* alloc channel */
+	tdmac = devm_kzalloc(tdev->dev, sizeof(*tdmac), GFP_KERNEL);
+	if (!tdmac) {
+		dev_err(tdev->dev, "no free memory for DMA channels!\n");
+		return -ENOMEM;
+	}
+	if (irq)
+		tdmac->irq = irq + idx;
+	tdmac->dev	   = tdev->dev;
+	tdmac->chan.device = &tdev->device;
+	tdmac->idx	   = idx;
+	tdmac->type	   = type;
+	tdmac->reg_base	   = (unsigned long)tdev->base + idx * 4;
+	tdmac->status = DMA_SUCCESS;
+	tdev->tdmac[tdmac->idx] = tdmac;
+	tasklet_init(&tdmac->tasklet, dma_do_tasklet, (unsigned long)tdmac);
+
+	/* add the channel to tdma_chan list */
+	list_add_tail(&tdmac->chan.device_node,
+			&tdev->device.channels);
+
+	return 0;
+}
+
+static int __devinit mmp_tdma_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	enum mmp_tdma_type type = id->driver_data;
+	struct mmp_tdma_device *tdev;
+	struct resource *iores;
+	int i, ret;
+	int irq = 0;
+	int chan_num = TDMA_CHANNEL_NUM;
+
+	/* always have couple channels */
+	tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
+	if (!tdev)
+		return -ENOMEM;
+
+	tdev->dev = &pdev->dev;
+	iores = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!iores)
+		return -EINVAL;
+
+	if (resource_size(iores) != chan_num)
+		tdev->irq = iores->start;
+	else
+		irq = iores->start;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iores)
+		return -EINVAL;
+
+	tdev->base = devm_request_and_ioremap(&pdev->dev, iores);
+	if (!tdev->base)
+		return -EADDRNOTAVAIL;
+
+	if (tdev->irq) {
+		ret = devm_request_irq(&pdev->dev, tdev->irq,
+			mmp_tdma_int_handler, IRQF_DISABLED, "tdma", tdev);
+		if (ret)
+			return ret;
+	}
+
+	dma_cap_set(DMA_SLAVE, tdev->device.cap_mask);
+	dma_cap_set(DMA_CYCLIC, tdev->device.cap_mask);
+
+	INIT_LIST_HEAD(&tdev->device.channels);
+
+	/* initialize channel parameters */
+	for (i = 0; i < chan_num; i++) {
+		ret = mmp_tdma_chan_init(tdev, i, irq, type);
+		if (ret)
+			return ret;
+	}
+
+	tdev->device.dev = &pdev->dev;
+	tdev->device.device_alloc_chan_resources =
+					mmp_tdma_alloc_chan_resources;
+	tdev->device.device_free_chan_resources =
+					mmp_tdma_free_chan_resources;
+	tdev->device.device_prep_slave_sg = mmp_tdma_prep_slave_sg;
+	tdev->device.device_prep_dma_cyclic = mmp_tdma_prep_dma_cyclic;
+	tdev->device.device_tx_status = mmp_tdma_tx_status;
+	tdev->device.device_issue_pending = mmp_tdma_issue_pending;
+	tdev->device.device_control = mmp_tdma_control;
+	tdev->device.copy_align = TDMA_ALIGNMENT;
+
+	dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	platform_set_drvdata(pdev, tdev);
+
+	ret = dma_async_device_register(&tdev->device);
+	if (ret) {
+		dev_err(tdev->device.dev, "unable to register\n");
+		return ret;
+	}
+
+	dev_info(tdev->device.dev, "initialized\n");
+	return 0;
+}
+
+static const struct platform_device_id mmp_tdma_id_table[] = {
+	{ "mmp-adma",	MMP_AUD_TDMA },
+	{ "pxa910-squ",	PXA910_SQU },
+	{ },
+};
+
+static struct platform_driver mmp_tdma_driver = {
+	.driver		= {
+		.name	= "mmp-tdma",
+		.owner  = THIS_MODULE,

drivers/dma/mmp_tdma.c line 649

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+	},
+	.id_table	= mmp_tdma_id_table,
+	.probe		= mmp_tdma_probe,
+	.remove		= __devexit_p(mmp_tdma_remove),
+};
+
+module_platform_driver(mmp_tdma_driver);
+
+MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
+MODULE_LICENSE("GPL");

AUTHOR, ALIAS too pls

Quoted 16 lines
include/linux/platform_data/mmp_dma.h new file +10 -0
new file mode 100644
index 0000000..4e21cf9
@@ -0,0 +1,20 @@
+/*
+ *  MMP Platform DMA Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */

include/linux/platform_data/mmp_dma.h line 20

Quoted 10 lines
include/linux/platform_data/mmp_dma.h new file +10 -0
+
+#ifndef MMP_DMA_H
+#define MMP_DMA_H
+
+struct mmp_tdma_data {
+	u32 bus_size;
+	u32 pack_mod;
+};
+
+#endif /* MMP_DMA_H */

why do you need separate header for this?

Signature · 1 line
~Vinod
#3 lore raw

Re: [PATCH v1 1/5] dmaengine: mmp_tdma: add mmp tdma support

Quoted 9 lines · Vinod Koul
Quoted 6 lines · Zhangfei Gao

Add support for two-channel dma under dmaengine
support: mmp-adma and pxa910-squ

Quoted 12 lines

Review

Quoted 11 lines
(quoted diff) +11 -0
+
+static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
+{
+ ? ? u32 reg = readl(tdmac->reg_base + TDISR);
+
+ ? ? if (reg & TDISR_COMP) {
+ ? ? ? ? ? ? /* clear irq */
+ ? ? ? ? ? ? reg &= ~TDISR_COMP;
+ ? ? ? ? ? ? writel(reg, tdmac->reg_base + TDISR);
+
+ ? ? ? ? ? ? return 1;

hrmm.?

This is local function used to check whether this channel has irq then return 1. Used by chan_handler.

Quoted 58 lines
Quoted 58 lines

+ ? ? }
+ ? ? return 0;

(quoted diff) +56 -0
+}
+
+static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
+{
+ ? ? struct mmp_tdma_chan *tdmac = dev_id;
+
+ ? ? if (mmp_tdma_clear_chan_irq(tdmac)) {
+ ? ? ? ? ? ? tdmac->pos = (tdmac->pos + tdmac->period_len) % tdmac->buf_len;
+ ? ? ? ? ? ? tasklet_schedule(&tdmac->tasklet);
+ ? ? ? ? ? ? return IRQ_HANDLED;
+ ? ? } else
+ ? ? ? ? ? ? return IRQ_NONE;
+}
+
+static irqreturn_t mmp_tdma_int_handler(int irq, void *dev_id)
+{
+ ? ? struct mmp_tdma_device *tdev = dev_id;
+ ? ? int i, ret;
+ ? ? int irq_num = 0;
+
+ ? ? for (i = 0; i < TDMA_CHANNEL_NUM; i++) {
+ ? ? ? ? ? ? struct mmp_tdma_chan *tdmac = tdev->tdmac[i];
+
+ ? ? ? ? ? ? ret = mmp_tdma_chan_handler(irq, tdmac);
+ ? ? ? ? ? ? if (ret == IRQ_HANDLED)
+ ? ? ? ? ? ? ? ? ? ? irq_num++;
+ ? ? }
+
+ ? ? if (irq_num)
+ ? ? ? ? ? ? return IRQ_HANDLED;
+ ? ? else
+ ? ? ? ? ? ? return IRQ_NONE;
+}
+
+static void dma_do_tasklet(unsigned long data)
+{
+ ? ? struct mmp_tdma_chan *tdmac = (struct mmp_tdma_chan *)data;
+
+ ? ? if (tdmac->desc.callback)
+ ? ? ? ? ? ? tdmac->desc.callback(tdmac->desc.callback_param);
+
+}
+
+static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
+{
+ ? ? struct gen_pool *gpool;
+ ? ? int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+ ? ? gpool = sram_get_gpool("asram");
+ ? ? if (tdmac->desc_arr)
+ ? ? ? ? ? ? gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? size);
+ ? ? tdmac->desc_arr = NULL;
+
+ ? ? return;
+}
Quoted 8 lines

drivers/dma/mmp_tdma.c

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static dma_cookie_t mmp_tdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ ? ? struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(tx->chan);
+
+ ? ? mmp_tdma_chan_set_desc(tdmac, tdmac->desc_arr_phys);

This seems odd. In submit you are supposed to move this to your pending list. Btw where is the .issue_pending handler?

The driver is specifically for audio.
So we make it simple, only support cylic method and no pending list at all. Only support sync mode.
tx_submit will directly write dma address with single descriptor chain. .issue_pending will directly start the dma.
When dma started, it will keep process data from/to user.

Quoted 15 lines
Quoted 15 lines
drivers/dma/mmp_tdma.c new file +15 -0
+
+ ? ? return 0;
+}
+
+static int mmp_tdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ ? ? struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+ ? ? int ret;
+
+ ? ? dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+ ? ? dma_async_tx_descriptor_init(&tdmac->desc, chan);
+ ? ? tdmac->desc.tx_submit = mmp_tdma_tx_submit;
+
+ ? ? if (tdmac->irq) {
Quoted 8 lines
Quoted 7 lines

+ ? ? ? ? ? ? ret = devm_request_irq(tdmac->dev, tdmac->irq,
+ ? ? ? ? ? ? ? ? ? ? mmp_tdma_chan_handler, IRQF_DISABLED, "tdma", tdmac);
+ ? ? ? ? ? ? if (ret)
+ ? ? ? ? ? ? ? ? ? ? goto err_request_irq;
+ ? ? }
+
+ ? ? return 0;

NO. This is supposed to return the number of descriptors allocated.

Thanks for remainder.

Quoted 10 lines

Review

Quoted 9 lines
(quoted diff) +9 -0
+static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
+{
+ ? ? struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+ ? ? dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+ ? ? if (tdmac->irq)
+ ? ? ? ? ? ? devm_free_irq(tdmac->dev, tdmac->irq, tdmac);
+ ? ? mmp_tdma_disable_chan(tdmac);

channel should be already disabled, why do you need this here?

Is there case directly call dma_put_channel without DMA_TERMINATE_ALL?

Quoted 11 lines
Quoted 11 lines

+ ? ? mmp_tdma_free_descriptor(tdmac);
+ ? ? return;

drivers/dma/mmp_tdma.c new file +9 -0
+}
+
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_slave_sg(
+ ? ? ? ? ? ? struct dma_chan *chan, struct scatterlist *sgl,
+ ? ? ? ? ? ? unsigned int sg_len, enum dma_transfer_direction direction,
+ ? ? ? ? ? ? unsigned long flags, void *context)
+{
+ ? ? /*
Quoted 8 lines
Quoted 7 lines

+ ? ? ?* This operation is not supported on the TDMA controller
+ ? ? ?*
+ ? ? ?* However, we need to provide the function pointer to allow the
+ ? ? ?* device_control() method to work.
+ ? ? ?*/
+ ? ? return NULL;
+}

Pls remove if not supported

Got it, my mistake,
confused by
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&

                !device->device_control);
Quoted 13 lines
Quoted 13 lines
(quoted diff) +13 -0
+
+static int mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+{
+ ? ? struct gen_pool *gpool;
+ ? ? int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+ ? ? dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+ ? ? gpool = sram_get_gpool("asram");
+ ? ? if (!gpool)
+ ? ? ? ? ? ? return -ENOMEM;
+
+ ? ? tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size);
Quoted 8 lines

Review

Quoted 7 lines

+ ? ? if (!tdmac->desc_arr)
+ ? ? ? ? ? ? return -ENOMEM;

(quoted diff) +5 -0
+
+ ? ? tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool,
+ ? ? ? ? ? ? ? ? ? ? (unsigned long)tdmac->desc_arr);
+
+ ? ? return 0;

this needs fix

Could you give more hints?

Quoted 24 lines
Quoted 13 lines
(quoted diff) +13 -0
+}
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
+ ? ? ? ? ? ? struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ ? ? ? ? ? ? size_t period_len, enum dma_transfer_direction direction,
+ ? ? ? ? ? ? void *context)
+{
+ ? ? struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+ ? ? int num_periods = buf_len / period_len;
+ ? ? int i = 0, buf = 0;
+ ? ? int ret;
+
+ ? ? if (tdmac->status != DMA_SUCCESS)

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? ? ? ? ? return NULL;
+
+ ? ? if (period_len > TDMA_MAX_XFER_BYTES) {
+ ? ? ? ? ? ? dev_err(tdmac->dev,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? "maximum period size exceeded: %d > %d\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? period_len, TDMA_MAX_XFER_BYTES);
+ ? ? ? ? ? ? goto err_out;
+ ? ? }
+
+ ? ? tdmac->status = DMA_IN_PROGRESS;

???

Quoted 8 lines
Quoted 7 lines

+ ? ? tdmac->desc_num = num_periods;
+ ? ? ret = mmp_tdma_alloc_descriptor(tdmac);
+ ? ? if (ret < 0)
+ ? ? ? ? ? ? goto err_out;
+
+ ? ? while (buf < buf_len) {
+ ? ? ? ? ? ? struct mmp_tdma_desc *desc = &tdmac->desc_arr[i];

what if i call prepare twice on the same channel?

We use tdmac->status to prevent calling again during transfering except the resource is freed.
Usually once cyclic dma is build, only data comming and out, without rebuild dma chain.
Here dma chain is simple, does not support asyn mode.

Quoted 10 lines

Better way would to manage a descriptor list, see other drivers for examples.

Quoted 6 lines

+
+ ? ? ? ? ? ? if (i + 1 == num_periods)
+ ? ? ? ? ? ? ? ? ? ? desc->nxt_desc = tdmac->desc_arr_phys;
+ ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? desc->nxt_desc = tdmac->desc_arr_phys +
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof(*desc) * (i + 1);

pls use kernel link list, it is provided to you so that you dont have to do above.

We have limitation for hardware.
SRAM has to be used for both dma buffer and dma descriptor. While SRAM is very very limited on some platform, as a result link node may not able to be allocated. So we simply organize descriptor physically one by one.

Quoted 8 lines

drivers/dma/mmp_tdma.c

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static void mmp_tdma_issue_pending(struct dma_chan *chan)
+{
+ ? ? struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+ ? ? mmp_tdma_enable_chan(tdmac);

can you queue the descriptors here? That was purpose to have separate issue pending and submit.

Since the SRAM is limited, I am afraid it can not allocate memory for queue. And to make it simple, we just arrange descriptor one by one.

Quoted 6 lines

drivers/dma/mmp_tdma.c line 649

Quoted 5 lines
drivers/dma/mmp_tdma.c new file +5 -0
+
+module_platform_driver(mmp_tdma_driver);
+
+MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
+MODULE_LICENSE("GPL");

AUTHOR, ALIAS too pls

Thanks, got it.

Quoted 20 lines
Quoted 20 lines
include/linux/platform_data/mmp_dma.h new file +13 -0
new file mode 100644
index 0000000..4e21cf9
@@ -0,0 +1,20 @@
+/*
+ * ?MMP Platform DMA Management
+ *
+ * ?Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ * ?This program is free software; you can redistribute it and/or modify
+ * ?it under the terms of the GNU General Public License version 2 as
+ * ?published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_DMA_H
+#define MMP_DMA_H
Quoted 8 lines

include/linux/platform_data/mmp_dma.h line 20

Quoted 7 lines
include/linux/platform_data/mmp_dma.h new file +7 -0
+
+struct mmp_tdma_data {
+ ? ? u32 bus_size;
+ ? ? u32 pack_mod;
+};
+
+#endif /* MMP_DMA_H */

why do you need separate header for this?

The structure is sharing private config between dma driver and pcm driver under sound.
The header file will be expanded for other dma driver.

Quoted 5 lines

--
~Vinod

#4 lore raw

Re: [PATCH v1 1/5] dmaengine: mmp_tdma: add mmp tdma support

Quoted 11 lines · zhangfei gao
Quoted 11 lines

drivers/dma/mmp_tdma.c line 259

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
+{
+     u32 reg = readl(tdmac->reg_base + TDISR);
+
+     if (reg & TDISR_COMP) {
+             /* clear irq */
+             reg &= ~TDISR_COMP;
+             writel(reg, tdmac->reg_base + TDISR);
+
+             return 1;

hrmm.?

Quoted 2 lines

This is local function used to check whether this channel has irq then return 1. Used by chan_handler.

quite linux unlike.

Quoted 9 lines
Quoted 8 lines

drivers/dma/mmp_tdma.c line 323

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static dma_cookie_t mmp_tdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(tx->chan);
+
+     mmp_tdma_chan_set_desc(tdmac, tdmac->desc_arr_phys);

This seems odd. In submit you are supposed to move this to your pending list. Btw where is the .issue_pending handler?

Quoted 6 lines

The driver is specifically for audio.
So we make it simple, only support cylic method and no pending list at all. Only support sync mode.
tx_submit will directly write dma address with single descriptor chain. .issue_pending will directly start the dma.
When dma started, it will keep process data from/to user.

But then you are putting unnecessary limitation on its use. Limiation should be based on h/w caps

Quoted 38 lines
Quoted 16 lines
Quoted 16 lines
drivers/dma/mmp_tdma.c new file +15 -0
+
+     return 0;
+}
+
+static int mmp_tdma_alloc_chan_resources(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+     int ret;
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     dma_async_tx_descriptor_init(&tdmac->desc, chan);
+     tdmac->desc.tx_submit = mmp_tdma_tx_submit;
+
+     if (tdmac->irq) {
Quoted 8 lines

drivers/dma/mmp_tdma.c line 345

Quoted 7 lines
drivers/dma/mmp_tdma.c new file +7 -0
+             ret = devm_request_irq(tdmac->dev, tdmac->irq,
+                     mmp_tdma_chan_handler, IRQF_DISABLED, "tdma", tdmac);
+             if (ret)
+                     goto err_request_irq;
+     }
+
+     return 0;

NO. This is supposed to return the number of descriptors allocated.

Thanks for remainder.

Quoted 10 lines

drivers/dma/mmp_tdma.c line 360

Quoted 9 lines
drivers/dma/mmp_tdma.c new file +9 -0
+static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     if (tdmac->irq)
+             devm_free_irq(tdmac->dev, tdmac->irq, tdmac);
+     mmp_tdma_disable_chan(tdmac);

channel should be already disabled, why do you need this here?

Quoted 1 line

Is there case directly call dma_put_channel without DMA_TERMINATE_ALL?

in cyclic no, otherwise yes.

Quoted 47 lines
Quoted 12 lines
Quoted 12 lines
drivers/dma/mmp_tdma.c new file +11 -0
+     mmp_tdma_free_descriptor(tdmac);
+     return;
+}
+
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_slave_sg(
+             struct dma_chan *chan, struct scatterlist *sgl,
+             unsigned int sg_len, enum dma_transfer_direction direction,
+             unsigned long flags, void *context)
+{
+     /*
Quoted 8 lines

drivers/dma/mmp_tdma.c line 378

Quoted 7 lines
drivers/dma/mmp_tdma.c new file +7 -0
+      * This operation is not supported on the TDMA controller
+      *
+      * However, we need to provide the function pointer to allow the
+      * device_control() method to work.
+      */
+     return NULL;
+}

Pls remove if not supported

Got it, my mistake,
confused by
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&

                !device->device_control);
Quoted 13 lines
Quoted 13 lines
drivers/dma/mmp_tdma.c new file +13 -0
+
+static int mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+{
+     struct gen_pool *gpool;
+     int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     gpool = sram_get_gpool("asram");
+     if (!gpool)
+             return -ENOMEM;
+
+     tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size);
Quoted 8 lines

drivers/dma/mmp_tdma.c line 398

Quoted 7 lines
drivers/dma/mmp_tdma.c new file +7 -0
+     if (!tdmac->desc_arr)
+             return -ENOMEM;
+
+     tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool,
+                     (unsigned long)tdmac->desc_arr);
+
+     return 0;

this needs fix

Quoted 1 line

Could you give more hints?

return the descriptors allocated

Quoted 48 lines
Quoted 25 lines
Quoted 14 lines
drivers/dma/mmp_tdma.c new file +13 -0
+}
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
+             struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+             size_t period_len, enum dma_transfer_direction direction,
+             void *context)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+     int num_periods = buf_len / period_len;
+     int i = 0, buf = 0;
+     int ret;
+
+     if (tdmac->status != DMA_SUCCESS)

drivers/dma/mmp_tdma.c line 421

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+             return NULL;
+
+     if (period_len > TDMA_MAX_XFER_BYTES) {
+             dev_err(tdmac->dev,
+                             "maximum period size exceeded: %d > %d\n",
+                             period_len, TDMA_MAX_XFER_BYTES);
+             goto err_out;
+     }
+
+     tdmac->status = DMA_IN_PROGRESS;

???

Quoted 8 lines

drivers/dma/mmp_tdma.c line 428

Quoted 7 lines
drivers/dma/mmp_tdma.c new file +7 -0
+     tdmac->desc_num = num_periods;
+     ret = mmp_tdma_alloc_descriptor(tdmac);
+     if (ret < 0)
+             goto err_out;
+
+     while (buf < buf_len) {
+             struct mmp_tdma_desc *desc = &tdmac->desc_arr[i];

what if i call prepare twice on the same channel?

We use tdmac->status to prevent calling again during transfering except the resource is freed.
Usually once cyclic dma is build, only data comming and out, without rebuild dma chain.
Here dma chain is simple, does not support asyn mode.

Quoted 8 lines

Better way would to manage a descriptor list, see other drivers for examples.

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+             if (i + 1 == num_periods)
+                     desc->nxt_desc = tdmac->desc_arr_phys;
+             else
+                     desc->nxt_desc = tdmac->desc_arr_phys +
+                             sizeof(*desc) * (i + 1);
Quoted 8 lines
Quoted 2 lines

pls use kernel link list, it is provided to you so that you dont have to do above.

We have limitation for hardware.
SRAM has to be used for both dma buffer and dma descriptor. While SRAM is very very limited on some platform, as a result link node may not able to be allocated. So we simply organize descriptor physically one by one.

You can embed your h/w descriptor in your list structure, managing them becomes easy.

Quoted 52 lines
Quoted 10 lines

drivers/dma/mmp_tdma.c line 508

Quoted 8 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static void mmp_tdma_issue_pending(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+     mmp_tdma_enable_chan(tdmac);

can you queue the descriptors here? That was purpose to have separate issue pending and submit.

Since the SRAM is limited, I am afraid it can not allocate memory for queue. And to make it simple, we just arrange descriptor one by one.

Quoted 6 lines

drivers/dma/mmp_tdma.c line 649

Quoted 5 lines
drivers/dma/mmp_tdma.c new file +5 -0
+
+module_platform_driver(mmp_tdma_driver);
+
+MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
+MODULE_LICENSE("GPL");

AUTHOR, ALIAS too pls

Thanks, got it.

Quoted 20 lines
Quoted 20 lines
include/linux/platform_data/mmp_dma.h new file +13 -0
new file mode 100644
index 0000000..4e21cf9
@@ -0,0 +1,20 @@
+/*
+ *  MMP Platform DMA Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_DMA_H
+#define MMP_DMA_H
Quoted 8 lines

include/linux/platform_data/mmp_dma.h line 20

Quoted 7 lines
include/linux/platform_data/mmp_dma.h new file +7 -0
+
+struct mmp_tdma_data {
+     u32 bus_size;
+     u32 pack_mod;
+};
+
+#endif /* MMP_DMA_H */

why do you need separate header for this?

Quoted 3 lines

The structure is sharing private config between dma driver and pcm driver under sound.
The header file will be expanded for other dma driver.

Other?

Signature · 1 line
~Vinod
#5 lore raw

Re: [PATCH v1 1/5] dmaengine: mmp_tdma: add mmp tdma support

Quoted 173 lines · Vinod Koul
Quoted 11 lines · zhangfei gao
Quoted 11 lines

drivers/dma/mmp_tdma.c line 259

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+static int mmp_tdma_clear_chan_irq(struct mmp_tdma_chan *tdmac)
+{
+     u32 reg = readl(tdmac->reg_base + TDISR);
+
+     if (reg & TDISR_COMP) {
+             /* clear irq */
+             reg &= ~TDISR_COMP;
+             writel(reg, tdmac->reg_base + TDISR);
+
+             return 1;

hrmm.?

Quoted 2 lines

This is local function used to check whether this channel has irq then return 1. Used by chan_handler.

quite linux unlike.

Quoted 9 lines
Quoted 8 lines

drivers/dma/mmp_tdma.c line 323

Quoted 6 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static dma_cookie_t mmp_tdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(tx->chan);
+
+     mmp_tdma_chan_set_desc(tdmac, tdmac->desc_arr_phys);

This seems odd. In submit you are supposed to move this to your pending list. Btw where is the .issue_pending handler?

Quoted 6 lines

The driver is specifically for audio.
So we make it simple, only support cylic method and no pending list at all. Only support sync mode.
tx_submit will directly write dma address with single descriptor chain. .issue_pending will directly start the dma.
When dma started, it will keep process data from/to user.

But then you are putting unnecessary limitation on its use. Limiation should be based on h/w caps

Quoted 38 lines
Quoted 16 lines
Quoted 16 lines
drivers/dma/mmp_tdma.c new file +15 -0
+
+     return 0;
+}
+
+static int mmp_tdma_alloc_chan_resources(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+     int ret;
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     dma_async_tx_descriptor_init(&tdmac->desc, chan);
+     tdmac->desc.tx_submit = mmp_tdma_tx_submit;
+
+     if (tdmac->irq) {
Quoted 8 lines
Quoted 7 lines

+             ret = devm_request_irq(tdmac->dev, tdmac->irq,
+                     mmp_tdma_chan_handler, IRQF_DISABLED, "tdma", tdmac);
+             if (ret)
+                     goto err_request_irq;
+     }
+
+     return 0;

NO. This is supposed to return the number of descriptors allocated.

Thanks for remainder.

Quoted 10 lines

drivers/dma/mmp_tdma.c line 360

Quoted 9 lines
drivers/dma/mmp_tdma.c new file +9 -0
+static void mmp_tdma_free_chan_resources(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     if (tdmac->irq)
+             devm_free_irq(tdmac->dev, tdmac->irq, tdmac);
+     mmp_tdma_disable_chan(tdmac);

channel should be already disabled, why do you need this here?

Quoted 1 line

Is there case directly call dma_put_channel without DMA_TERMINATE_ALL?

in cyclic no, otherwise yes.

Quoted 47 lines
Quoted 12 lines
Quoted 12 lines

+     mmp_tdma_free_descriptor(tdmac);
+     return;

drivers/dma/mmp_tdma.c new file +9 -0
+}
+
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_slave_sg(
+             struct dma_chan *chan, struct scatterlist *sgl,
+             unsigned int sg_len, enum dma_transfer_direction direction,
+             unsigned long flags, void *context)
+{
+     /*
Quoted 8 lines
Quoted 7 lines

+      * This operation is not supported on the TDMA controller
+      *
+      * However, we need to provide the function pointer to allow the
+      * device_control() method to work.
+      */
+     return NULL;
+}

Pls remove if not supported

Got it, my mistake,
confused by
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && !device->device_control);

Quoted 13 lines
Quoted 13 lines
drivers/dma/mmp_tdma.c new file +13 -0
+
+static int mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
+{
+     struct gen_pool *gpool;
+     int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
+
+     dev_dbg(tdmac->dev, "%s: enter\n", __func__);
+
+     gpool = sram_get_gpool("asram");
+     if (!gpool)
+             return -ENOMEM;
+
+     tdmac->desc_arr = (void *)gen_pool_alloc(gpool, size);
Quoted 8 lines

drivers/dma/mmp_tdma.c line 398

Quoted 7 lines

+     if (!tdmac->desc_arr)
+             return -ENOMEM;

drivers/dma/mmp_tdma.c new file +5 -0
+
+     tdmac->desc_arr_phys = gen_pool_virt_to_phys(gpool,
+                     (unsigned long)tdmac->desc_arr);
+
+     return 0;

this needs fix

Quoted 1 line

Could you give more hints?

return the descriptors allocated

Quoted 51 lines
Quoted 25 lines
Quoted 14 lines
drivers/dma/mmp_tdma.c new file +13 -0
+}
+
+static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
+             struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+             size_t period_len, enum dma_transfer_direction direction,
+             void *context)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+     int num_periods = buf_len / period_len;
+     int i = 0, buf = 0;
+     int ret;
+
+     if (tdmac->status != DMA_SUCCESS)

drivers/dma/mmp_tdma.c line 421

Quoted 10 lines
drivers/dma/mmp_tdma.c new file +10 -0
+             return NULL;
+
+     if (period_len > TDMA_MAX_XFER_BYTES) {
+             dev_err(tdmac->dev,
+                             "maximum period size exceeded: %d > %d\n",
+                             period_len, TDMA_MAX_XFER_BYTES);
+             goto err_out;
+     }
+
+     tdmac->status = DMA_IN_PROGRESS;

???

Quoted 8 lines
Quoted 7 lines

+     tdmac->desc_num = num_periods;
+     ret = mmp_tdma_alloc_descriptor(tdmac);
+     if (ret < 0)
+             goto err_out;
+
+     while (buf < buf_len) {
+             struct mmp_tdma_desc *desc = &tdmac->desc_arr[i];

what if i call prepare twice on the same channel?

We use  tdmac->status to prevent calling again during transfering except the resource is freed.
Usually once cyclic dma is build, only data comming and out, without rebuild dma chain.
Here dma chain is simple, does not support asyn mode.

Quoted 10 lines

Better way would to manage a descriptor list, see other drivers for examples.

Quoted 6 lines

+
+             if (i + 1 == num_periods)
+                     desc->nxt_desc = tdmac->desc_arr_phys;
+             else
+                     desc->nxt_desc = tdmac->desc_arr_phys +
+                             sizeof(*desc) * (i + 1);

pls use kernel link list, it is provided to you so that you dont have to do above.

Quoted 7 lines
Quoted 5 lines

We have limitation for hardware.
SRAM has to be used for both dma buffer and dma descriptor. While SRAM is very very limited on some platform, as a result link node may not able to be allocated. So we simply organize descriptor physically one by one.

You can embed your h/w descriptor in your list structure, managing them becomes easy.

Thanks Vinod.

Our plan is keep this audio dma driver as simple as possible Only support cyclic & sync mode,
And dma descriptor chain only build once, have no chance to re-organize. Then cyclic dma keep running and consuming/generating data.
SRAM have to be used, which is limited, but SRAM can work at low power mode. So maybe it is easier to organize statically.

We still have peripheral dma working on ddr, with different register and free usage.
It support async mode and have to use pending list, etc.

Quoted 60 lines
Quoted 52 lines
Quoted 10 lines

drivers/dma/mmp_tdma.c line 508

Quoted 8 lines
drivers/dma/mmp_tdma.c new file +6 -0
+
+static void mmp_tdma_issue_pending(struct dma_chan *chan)
+{
+     struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+     mmp_tdma_enable_chan(tdmac);

can you queue the descriptors here? That was purpose to have separate issue pending and submit.

Since the SRAM is limited, I am afraid it can not allocate memory for queue. And to make it simple, we just arrange descriptor one by one.

Quoted 6 lines

drivers/dma/mmp_tdma.c line 649

Quoted 5 lines
drivers/dma/mmp_tdma.c new file +5 -0
+
+module_platform_driver(mmp_tdma_driver);
+
+MODULE_DESCRIPTION("MMP Two-Channel DMA Driver");
+MODULE_LICENSE("GPL");

AUTHOR, ALIAS too pls

Thanks, got it.

Quoted 20 lines
Quoted 20 lines
include/linux/platform_data/mmp_dma.h new file +13 -0
new file mode 100644
index 0000000..4e21cf9
@@ -0,0 +1,20 @@
+/*
+ *  MMP Platform DMA Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_DMA_H
+#define MMP_DMA_H
Quoted 8 lines

include/linux/platform_data/mmp_dma.h line 20

Quoted 7 lines
include/linux/platform_data/mmp_dma.h new file +7 -0
+
+struct mmp_tdma_data {
+     u32 bus_size;
+     u32 pack_mod;
+};
+
+#endif /* MMP_DMA_H */

why do you need separate header for this?

Quoted 3 lines

The structure is sharing private config between dma driver and pcm driver under sound.
The header file will be expanded for other dma driver.

Other?

--
~Vinod

#6 lore raw

PATCH 2/5 ASoC: mmp: add audio dma support

In reply to Zhangfei Gao

mmp-pcm handle audio dma based on soc-dmaengine
Support mmp and pxa910

---
 include/linux/platform_data/mmp_audio.h |   22 ++
 sound/soc/pxa/Kconfig                   |    9 +
 sound/soc/pxa/Makefile                  |    2 +
 sound/soc/pxa/mmp-pcm.c                 |  317 +++++++++++++++++++++++++++++++
 4 files changed, 350 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/platform_data/mmp_audio.h
 create mode 100644 sound/soc/pxa/mmp-pcm.c
include/linux/platform_data/mmp_audio.h new file +22 -0
new file mode 100644
index 0000000..0f25d16
@@ -0,0 +1,22 @@
+/*
+ *  MMP Platform AUDIO Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_AUDIO_H
+#define MMP_AUDIO_H
+
+struct mmp_audio_platdata {
+	u32 period_max_capture;
+	u32 buffer_max_capture;
+	u32 period_max_playback;
+	u32 buffer_max_playback;
+};
+
+#endif /* MMP_AUDIO_H */
sound/soc/pxa/Kconfig +9 -0
index a0f7d3c..5d76e29 100644
@@ -8,6 +8,15 @@ config SND_PXA2XX_SOC
 	  the PXA2xx AC97, I2S or SSP interface. You will also need
 	  to select the audio interfaces to support below.
 
+config SND_MMP_SOC
+	bool "Soc Audio for Marvell MMP chips"
+	depends on ARCH_MMP
+	select SND_SOC_DMAENGINE_PCM
+	select SND_ARM
+	help
+	  Say Y if you want to add support for codecs attached to
+	  the MMP SSPA interface.
+
 config SND_PXA2XX_AC97
 	tristate
 	select SND_AC97_CODEC
sound/soc/pxa/Makefile +2 -0
index af35762..f913e9b 100644
@@ -3,11 +3,13 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
 snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
 snd-soc-pxa-ssp-objs := pxa-ssp.o
+snd-soc-mmp-objs := mmp-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
 obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
+obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
 
 # PXA Machine Support
 snd-soc-corgi-objs := corgi.o
sound/soc/pxa/mmp-pcm.c new file +317 -0

317 lines not on this page · raw message

Signature · 1 line
1.7.1
#7 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 2 lines · Zhangfei Gao

mmp-pcm handle audio dma based on soc-dmaengine
Support mmp and pxa910

See soc-dmaengine.c. You sneed to use the library to use dmaengine.

Quoted 402 lines
---
 include/linux/platform_data/mmp_audio.h |   22 ++
 sound/soc/pxa/Kconfig                   |    9 +
 sound/soc/pxa/Makefile                  |    2 +
 sound/soc/pxa/mmp-pcm.c                 |  317 +++++++++++++++++++++++++++++++
 4 files changed, 350 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/platform_data/mmp_audio.h
 create mode 100644 sound/soc/pxa/mmp-pcm.c
include/linux/platform_data/mmp_audio.h new file +22 -0
new file mode 100644
index 0000000..0f25d16
@@ -0,0 +1,22 @@
+/*
+ *  MMP Platform AUDIO Management
+ *
+ *  Copyright (c) 2011 Marvell Semiconductors Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#ifndef MMP_AUDIO_H
+#define MMP_AUDIO_H
+
+struct mmp_audio_platdata {
+	u32 period_max_capture;
+	u32 buffer_max_capture;
+	u32 period_max_playback;
+	u32 buffer_max_playback;
+};
+
+#endif /* MMP_AUDIO_H */
sound/soc/pxa/Kconfig +9 -0
index a0f7d3c..5d76e29 100644
@@ -8,6 +8,15 @@ config SND_PXA2XX_SOC
 	  the PXA2xx AC97, I2S or SSP interface. You will also need
 	  to select the audio interfaces to support below.
 
+config SND_MMP_SOC
+	bool "Soc Audio for Marvell MMP chips"
+	depends on ARCH_MMP
+	select SND_SOC_DMAENGINE_PCM
+	select SND_ARM
+	help
+	  Say Y if you want to add support for codecs attached to
+	  the MMP SSPA interface.
+
 config SND_PXA2XX_AC97
 	tristate
 	select SND_AC97_CODEC
sound/soc/pxa/Makefile +2 -0
index af35762..f913e9b 100644
@@ -3,11 +3,13 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
 snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
 snd-soc-pxa-ssp-objs := pxa-ssp.o
+snd-soc-mmp-objs := mmp-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
 obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
+obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
 
 # PXA Machine Support
 snd-soc-corgi-objs := corgi.o
sound/soc/pxa/mmp-pcm.c new file +317 -0
new file mode 100644
index 0000000..b7b09f9
@@ -0,0 +1,317 @@
+/*
+ * linux/sound/soc/pxa/mmp-pcm.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/mmp_dma.h>
+#include <linux/platform_data/mmp_audio.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/sram.h>
+#include <sound/dmaengine_pcm.h>
+
+struct mmp_dma_data {
+	int ssp_id;
+	struct resource *dma_res;
+	struct mmp_tdma_data tdma_data;
+};
+
+#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP |	\
+		SNDRV_PCM_INFO_MMAP_VALID |	\
+		SNDRV_PCM_INFO_INTERLEAVED |	\
+		SNDRV_PCM_INFO_PAUSE |		\
+		SNDRV_PCM_INFO_RESUME)
+
+#define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			 SNDRV_PCM_FMTBIT_S24_LE | \
+			 SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_pcm_hardware mmp_pcm_hardware[] = {
+	{
+		.info			= MMP_PCM_INFO,
+		.formats		= MMP_PCM_FORMATS,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+	{
+		.info			= MMP_PCM_INFO,
+		.formats		= MMP_PCM_FORMATS,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+};
+
+static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct pxa2xx_pcm_dma_params *dma_params;
+	int ret;
+	struct dma_slave_config slave_config;
+
+	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	if (!dma_params)
+		return 0;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		dma_data->tdma_data.bus_size = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		dma_data->tdma_data.bus_size = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dma_data->tdma_data.bus_size = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		dma_data->tdma_data.bus_size = 32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dma_data->tdma_data.pack_mod = true;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.direction    = DMA_TO_DEVICE;
+		slave_config.dst_addr     = dma_params->dev_addr;
+		slave_config.dst_maxburst = 4;
+	} else {
+		slave_config.direction	  = DMA_FROM_DEVICE;
+		slave_config.src_addr	  = dma_params->dev_addr;
+		slave_config.src_maxburst = 4;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mmp_dma_data *dma_data = param;
+	bool found = false;
+	char *devname;
+
+	devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
+		dma_data->ssp_id);
+	if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+		(chan->chan_id == dma_data->dma_res->start)) {
+		chan->private = &dma_data->tdma_data;
+		found = true;
+	}
+
+	kfree(devname);
+	return found;
+}
+
+static int mmp_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct mmp_dma_data *dma_data;
+	struct resource *r;
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
+	if (!r)
+		return -EBUSY;
+
+	snd_soc_set_runtime_hwparams(substream,
+				&mmp_pcm_hardware[substream->stream]);
+	dma_data = devm_kzalloc(&pdev->dev,
+			sizeof(struct mmp_dma_data), GFP_KERNEL);
+	if (dma_data == NULL)
+		return -ENOMEM;
+
+	dma_data->dma_res = r;
+	dma_data->ssp_id = cpu_dai->id;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
+	if (ret) {
+		devm_kfree(&pdev->dev, dma_data);
+		return ret;
+	}
+
+	snd_dmaengine_pcm_set_data(substream, dma_data);
+	return 0;
+}
+
+static int mmp_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct platform_device *pdev = to_platform_device(rtd->platform->dev);
+
+	snd_dmaengine_pcm_close(substream);
+	devm_kfree(&pdev->dev, dma_data);
+	return 0;
+}
+
+static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
+			 struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long off = vma->vm_pgoff;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return remap_pfn_range(vma, vma->vm_start,
+		__phys_to_pfn(runtime->dma_addr) + off,
+		vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+struct snd_pcm_ops mmp_pcm_ops = {
+	.open		= mmp_pcm_open,
+	.close		= mmp_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= mmp_pcm_hw_params,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+	.mmap		= mmp_pcm_mmap,
+};
+
+static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+	struct gen_pool *gpool;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return;
+
+	for (stream = 0; stream < 2; stream++) {
+		size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		gen_pool_free(gpool, (unsigned long)buf->area, size);
+		buf->area = NULL;
+	}
+
+	return;
+}
+
+static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
+								int stream)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+	struct gen_pool *gpool;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = substream->pcm->card->dev;
+	buf->private_data = NULL;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return -ENOMEM;
+
+	buf->area = (unsigned char *)gen_pool_alloc(gpool, size);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area);
+	buf->bytes = size;
+	return 0;
+}
+
+int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret = 0, stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+
+		ret = mmp_pcm_preallocate_dma_buffer(substream,	stream);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	mmp_pcm_free_dma_buffers(pcm);
+	return ret;
+}
+
+struct snd_soc_platform_driver mmp_soc_platform = {
+	.ops		= &mmp_pcm_ops,
+	.pcm_new	= mmp_pcm_new,
+	.pcm_free	= mmp_pcm_free_dma_buffers,
+};
+
+static __devinit int mmp_pcm_probe(struct platform_device *pdev)
+{
+	struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
+
+	if (pdata) {
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
+						pdata->buffer_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
+						pdata->period_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
+						pdata->buffer_max_capture;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
+						pdata->period_max_capture;
+	}
+	return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
+}
+
+static int __devexit mmp_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver mmp_pcm_driver = {
+	.driver = {
+		.name = "mmp-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = mmp_pcm_probe,
+	.remove = __devexit_p(mmp_pcm_remove),
+};
+
+module_platform_driver(mmp_pcm_driver);
+
+MODULE_AUTHOR("Leo Yan <[email protected]>");
+MODULE_DESCRIPTION("MMP Soc Audio DMA module");
+MODULE_LICENSE("GPL");
Signature · 1 line
~Vinod
#8 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 5 lines · Vinod Koul
Quoted 2 lines · Zhangfei Gao

mmp-pcm handle audio dma based on soc-dmaengine
Support mmp and pxa910

See soc-dmaengine.c. You sneed to use the library to use dmaengine.

Thanks Vinod for kind review.

Some confusion, only find sound/soc/soc-dmaengine-pcm.c. So the driver base on the library, snd_dmaengine_pcm_open/close etc. Replacing dma_request_channel etc.

Is it right direction?

#9 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 7 lines · zhangfei gao
Quoted 5 lines · Vinod Koul
Quoted 2 lines · Zhangfei Gao

mmp-pcm handle audio dma based on soc-dmaengine
Support mmp and pxa910

See soc-dmaengine.c. You sneed to use the library to use dmaengine.

Quoted 7 lines

Thanks Vinod for kind review.

Some confusion, only find sound/soc/soc-dmaengine-pcm.c. So the driver base on the library, snd_dmaengine_pcm_open/close etc. Replacing dma_request_channel etc.

Is it right direction?

Yes your driver should use it. See examples in other soc drivers

Signature · 1 line
~Vinod
#10 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 8 lines · Vinod Koul
Quoted 7 lines · zhangfei gao
Quoted 5 lines · Vinod Koul
Quoted 2 lines · Zhangfei Gao

mmp-pcm handle audio dma based on soc-dmaengine
Support mmp and pxa910

See soc-dmaengine.c. You sneed to use the library to use dmaengine.

Quoted 8 lines
Quoted 7 lines

Thanks Vinod for kind review.

Some confusion, only find sound/soc/soc-dmaengine-pcm.c. So the driver base on the library, snd_dmaengine_pcm_open/close etc. Replacing dma_request_channel etc.

Is it right direction?

Yes your driver should use it. See examples in other soc drivers

This driver already been ported to soc-dmaengine-pcm.c, refer mxs-pcm.c and imx-pcm-dma-mx2.c.
Using snd_dmaengine_pcm_open, snd_dmaengine_pcm_close, etc.
Only exception is dmaengine_slave_config, since we have some specific config.

Quoted 5 lines

--
~Vinod

#11 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 1 line · zhangfei gao

Only exception is dmaengine_slave_config, since we have some specific config.

And why?

sound/soc/pxa/mmp-pcm.c line 128

Quoted 11 lines
sound/soc/pxa/mmp-pcm.c new file +11 -0
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mmp_dma_data *dma_data = param;
+	bool found = false;
+	char *devname;
+
+	devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
+		dma_data->ssp_id);
+	if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+		(chan->chan_id == dma_data->dma_res->start)) {
+		chan->private = &dma_data->tdma_data;

chan->private is deprecated and should not be used

Quoted 6 lines
sound/soc/pxa/mmp-pcm.c new file +6 -0
+		found = true;
+	}
+
+	kfree(devname);
+	return found;
+}
Signature · 1 line
~Vinod
#12 lore raw

Re: [PATCH v1 2/5] ASoC: mmp: add audio dma support

Quoted 4 lines · Vinod Koul
Quoted 1 line · zhangfei gao

Only exception is dmaengine_slave_config, since we have some specific config.

And why?

Quoted 12 lines

sound/soc/pxa/mmp-pcm.c line 128

Quoted 11 lines
sound/soc/pxa/mmp-pcm.c new file +11 -0
+static bool filter(struct dma_chan *chan, void *param)
+{
+     struct mmp_dma_data *dma_data = param;
+     bool found = false;
+     char *devname;
+
+     devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
+             dma_data->ssp_id);
+     if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
+             (chan->chan_id == dma_data->dma_res->start)) {
+             chan->private = &dma_data->tdma_data;

chan->private is deprecated and should not be used

Thanks for the info, will update accordingly.
The concern is DMA_SLAVE_BUSWIDTH_4_BYTES is used for S20, S24, S32. And our controller handles differently, though they not seen much.

Besides, dmaengine_slave_config still have to be used for src/dst_addr and src/dst_maxburst.

Quoted 11 lines

sound/soc/pxa/mmp-pcm.c line 134

Quoted 6 lines

+             found = true;
+     }

sound/soc/pxa/mmp-pcm.c new file +4 -0
+
+     kfree(devname);
+     return found;
+}

--
~Vinod

#13 lore raw

PATCH 3/5 ASOC: mmp: add sspa support

In reply to Zhangfei Gao

The SSPA is a configurable multi-channel audio serial (TDM) interface. It's configurable at runtime to support up to 128 channels and the number of bits per sample: 8, 12, 16, 20, 24 and 32 bits. It also support stereo format: I2S, left-justified or right-justified.

---
 sound/soc/pxa/Kconfig    |    3 +
 sound/soc/pxa/Makefile   |    2 +
 sound/soc/pxa/mmp-sspa.c |  496 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/pxa/mmp-sspa.h |   92 +++++++++
 4 files changed, 593 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/pxa/mmp-sspa.c
 create mode 100644 sound/soc/pxa/mmp-sspa.h
sound/soc/pxa/Kconfig +3 -0
index 5d76e29..6c3d00b 100644
@@ -35,6 +35,9 @@ config SND_PXA_SOC_SSP
 	tristate
 	select PXA_SSP
 
+config SND_MMP_SOC_SSPA
+	tristate
+
 config SND_PXA2XX_SOC_CORGI
 	tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
 	depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx
sound/soc/pxa/Makefile +2 -0
index f913e9b..07b8417 100644
@@ -4,12 +4,14 @@ snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
 snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
 snd-soc-pxa-ssp-objs := pxa-ssp.o
 snd-soc-mmp-objs := mmp-pcm.o
+snd-soc-mmp-sspa-objs := mmp-sspa.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
 obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
 obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
 obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
 obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
+obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
 
 # PXA Machine Support
 snd-soc-corgi-objs := corgi.o
sound/soc/pxa/mmp-sspa.c new file +496 -0

496 lines not on this page · raw message

sound/soc/pxa/mmp-sspa.h new file +92 -0

92 lines not on this page · raw message

Signature · 1 line
1.7.1
#14 lore raw

PATCH 3/5 ASOC: mmp: add sspa support

Quoted 4 lines · Zhangfei Gao

The SSPA is a configurable multi-channel audio serial (TDM) interface. It's configurable at runtime to support up to 128 channels and the number of bits per sample: 8, 12, 16, 20, 24 and 32 bits. It also support stereo format: I2S, left-justified or right-justified.

This looks mostly good (though you want to check your indentation a bit) but...

sound/soc/pxa/mmp-sspa.c line 480

Quoted 10 lines
sound/soc/pxa/mmp-sspa.c new file +10 -0
+static int __init mmp_sspa_modinit(void)
+{
+	audio_clk = clk_get(NULL, "mmp-audio");
+	if (IS_ERR(audio_clk))
+		return PTR_ERR(audio_clk);
+
+	sysclk = clk_get(NULL, "mmp-sysclk");
+	if (IS_ERR(sysclk))
+		return PTR_ERR(sysclk);
+	clk_enable(audio_clk);

You should be doing this stuff from the driver, not from the module init
(and ideally you'd be managing the audio clock dynamically). Even if
it's the same clock every time in current silicon it's still a good idea
to do this from a quality of implementation point of view.
-------------- 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/20120608/7c7f2870/attachment-0001.sig>

#15 lore raw

Re: [PATCH v1 3/5] ASOC: mmp: add sspa support

Quoted 9 lines · Mark Brown
Quoted 4 lines · Zhangfei Gao

The SSPA is a configurable multi-channel audio serial (TDM) interface. It's configurable at runtime to support up to 128 channels and the number of bits per sample: 8, 12, 16, 20, 24 and 32 bits. It also support stereo format: I2S, left-justified or right-justified.

This looks mostly good (though you want to check your indentation a bit) but...

Quoted 15 lines

sound/soc/pxa/mmp-sspa.c line 480

Quoted 10 lines
sound/soc/pxa/mmp-sspa.c new file +10 -0
+static int __init mmp_sspa_modinit(void)
+{
+     audio_clk = clk_get(NULL, "mmp-audio");
+     if (IS_ERR(audio_clk))
+             return PTR_ERR(audio_clk);
+
+     sysclk = clk_get(NULL, "mmp-sysclk");
+     if (IS_ERR(sysclk))
+             return PTR_ERR(sysclk);
+     clk_enable(audio_clk);

You should be doing this stuff from the driver, not from the module init (and ideally you'd be managing the audio clock dynamically).  Even if it's the same clock every time in current silicon it's still a good idea to do this from a quality of implementation point of view.

Thanks, will remove the module init, and move clk staff to probe. However, dynamically control audio_clk make audio subsystem works abnormally.

#16 lore raw

Re: [PATCH v1 3/5] ASOC: mmp: add sspa support

In reply to Zhangfei Gao
Quoted 4 lines · Zhangfei Gao

The SSPA is a configurable multi-channel audio serial (TDM) interface. It's configurable at runtime to support up to 128 channels and the number of bits per sample: 8, 12, 16, 20, 24 and 32 bits. It also support stereo format: I2S, left-justified or right-justified.

This looks mostly good (though you want to check your indentation a bit) but...

sound/soc/pxa/mmp-sspa.c line 480

Quoted 10 lines
sound/soc/pxa/mmp-sspa.c new file +10 -0
+static int __init mmp_sspa_modinit(void)
+{
+	audio_clk = clk_get(NULL, "mmp-audio");
+	if (IS_ERR(audio_clk))
+		return PTR_ERR(audio_clk);
+
+	sysclk = clk_get(NULL, "mmp-sysclk");
+	if (IS_ERR(sysclk))
+		return PTR_ERR(sysclk);
+	clk_enable(audio_clk);

You should be doing this stuff from the driver, not from the module init (and ideally you'd be managing the audio clock dynamically). Even if it's the same clock every time in current silicon it's still a good idea to do this from a quality of implementation point of view.

#17 lore raw

PATCH 4/5 ASoC: add mmp brownstone support

In reply to Zhangfei Gao

Adds Alsa audio platform driver for mmp brownstone machine

---
 sound/soc/pxa/Kconfig      |   10 +++
 sound/soc/pxa/Makefile     |    2 +
 sound/soc/pxa/brownstone.c |  178 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/pxa/brownstone.c
sound/soc/pxa/Kconfig +10 -0
index 6c3d00b..d389fd5 100644
@@ -206,3 +206,13 @@ config SND_PXA2XX_SOC_IMOTE2
        help
          Say Y if you want to add support for SoC audio on the
 	 IMote 2.
+
+config SND_MMP_SOC_BROWNSTONE
+	tristate "SoC Audio support for Marvell Brownstone"
+	depends on SND_MMP_SOC && MACH_BROWNSTONE
+	select SND_MMP_SOC_SSPA
+	select MFD_WM8994
+	select SND_SOC_WM8994
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell Brownstone reference platform.
sound/soc/pxa/Makefile +2 -0
index 07b8417..c12aa2a 100644
@@ -32,6 +32,7 @@ snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-z2-objs := z2.o
 snd-soc-imote2-objs := imote2.o
 snd-soc-raumfeld-objs := raumfeld.o
+snd-soc-brownstone-objs := brownstone.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -51,3 +52,4 @@ obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
+obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
sound/soc/pxa/brownstone.c new file +178 -0

178 lines not on this page · raw message

Signature · 1 line
1.7.1
#18 lore raw

Re: [PATCH v1 4/5] ASoC: add mmp brownstone support

On Mon, Jun 04, 2012 at 02:37:30PM +0800, Zhangfei Gao wrote:

One small thing here...

sound/soc/pxa/brownstone.c line 57

Quoted 4 lines
sound/soc/pxa/brownstone.c new file +4 -0
+	ret = snd_soc_add_card_controls(dapm->card, brownstone_dapm_control,
+				   ARRAY_SIZE(brownstone_dapm_control));
+	if (ret < 0)
+		return ret;

You can just set these up with the controls member of the card struct.

#19 lore raw

Re: [PATCH v1 4/5] ASoC: add mmp brownstone support

Quoted 10 lines · Mark Brown

On Mon, Jun 04, 2012 at 02:37:30PM +0800, Zhangfei Gao wrote:

One small thing here...

Quoted 4 lines

+ ? ? ret = snd_soc_add_card_controls(dapm->card, brownstone_dapm_control,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?ARRAY_SIZE(brownstone_dapm_control));
+ ? ? if (ret < 0)
+ ? ? ? ? ? ? return ret;

You can just set these up with the controls member of the card struct.

Great, it will make it easier, thanks.

Quoted 6 lines

_______________________________________________
Alsa-devel mailing list
Alsa-devel at alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

#20 lore raw

PATCH 5/5 ASoC: add ttc-dkb machine support

In reply to Zhangfei Gao

From: Qiao Zhou <[email protected]>

add ttc-dkb machine support for pxa910. It uses 88pm8607 as codec dai, mmp-pcm as platform and pxa-ssp as cpu dai.

---
 sound/soc/pxa/Kconfig   |   20 ++++++
 sound/soc/pxa/Makefile  |    2 +
 sound/soc/pxa/ttc-dkb.c |  173 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/pxa/ttc-dkb.c
sound/soc/pxa/Kconfig +20 -0
index d389fd5..4d2e46f 100644
@@ -150,6 +150,26 @@ config SND_SOC_TAVOREVB3
 	  Say Y if you want to add support for SoC audio on the
 	  Marvell Saarb reference platform.
 
+config SND_PXA910_SOC
+	tristate "SoC Audio for Marvell PXA910 chip"
+	depends on ARCH_MMP && SND
+	select SND_PCM
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell PXA910 reference platform.
+
+config SND_SOC_TTC_DKB
+	bool "SoC Audio support for TTC DKB"
+	depends on SND_PXA910_SOC && MACH_TTC_DKB
+	select PXA_SSP
+	select SND_PXA_SOC_SSP
+	select SND_MMP_SOC
+	select MFD_88PM860X
+	select SND_SOC_88PM860X
+	help
+	  Say Y if you want to add support for SoC audio on TTC DKB
+
+
 config SND_SOC_ZYLONITE
 	tristate "SoC Audio support for Marvell Zylonite"
 	depends on SND_PXA2XX_SOC && MACH_ZYLONITE
sound/soc/pxa/Makefile +2 -0
index c12aa2a..d8a265d 100644
@@ -33,6 +33,7 @@ snd-soc-z2-objs := z2.o
 snd-soc-imote2-objs := imote2.o
 snd-soc-raumfeld-objs := raumfeld.o
 snd-soc-brownstone-objs := brownstone.o
+snd-soc-ttc-dkb-objs := ttc-dkb.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -53,3 +54,4 @@ obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
 obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
+obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
sound/soc/pxa/ttc-dkb.c new file +173 -0

173 lines not on this page · raw message

Signature · 1 line
1.7.1