ASoC: loongson: Separate external shared DMA from the platform interface

The Loongson I2S platform driver (used on LS2K1000, LS7A etc.) relies on
an external DMA engine (e.g., dw_dmac) rather than the internal DMA.
However, its DMA-related code was originally embedded in
loongson_i2s_plat.c, duplicating logic that should be shared.

Extract the external DMA (eDMA) support from the platform driver and move
it into loongson_dma.c alongside the existing internal DMA (iDMA) code.

This change eliminates code duplication and prepares for future
consolidation of DMA selection logic.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Link: https://patch.msgid.link/979368ad269f192703ed24e9a19eebce32316745.1780304703.git.zhoubinbin@loongson.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Binbin Zhou 2026-06-01 17:29:39 +08:00 committed by Mark Brown
parent 353530ece8
commit 767a1b50c1
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
4 changed files with 65 additions and 59 deletions

View File

@ -1,12 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
#Platform Support
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o
snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o
snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o
obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o
snd-soc-loongson-i2s-y := loongson_i2s.o
snd-soc-loongson-i2s-y := loongson_i2s.o loongson_dma.o
obj-$(CONFIG_SND_LOONGSON1_AC97) += loongson1_ac97.o

View File

@ -344,3 +344,62 @@ const struct snd_soc_component_driver loongson_i2s_idma_component = {
.mmap = loongson_idma_pcm_mmap,
.pcm_new = loongson_idma_pcm_new,
};
EXPORT_SYMBOL_GPL(loongson_i2s_idma_component);
static const struct snd_pcm_hardware loongson_edma_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE,
.period_bytes_min = 128,
.period_bytes_max = 128 * 1024,
.periods_min = 1,
.periods_max = 64,
.buffer_bytes_max = 1024 * 1024,
};
const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
.pcm_hardware = &loongson_edma_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.prealloc_buffer_size = 128 * 1024,
};
EXPORT_SYMBOL_GPL(loongson_dmaengine_pcm_config);
/* External DMA component */
static int loongson_edma_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (substream->pcm->device & 1) {
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
}
if (substream->pcm->device & 2)
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
/*
* For mysterious reasons (and despite what the manual says)
* playback samples are lost if the DMA count is not a multiple
* of the DMA burst size. Let's add a rule to enforce that.
*/
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
return 0;
}
const struct snd_soc_component_driver loongson_i2s_edma_component = {
.name = LS_I2S_DRVNAME,
.open = loongson_edma_pcm_open,
};
EXPORT_SYMBOL_GPL(loongson_i2s_edma_component);

View File

@ -10,5 +10,7 @@
#define _LOONGSON_DMA_H
extern const struct snd_soc_component_driver loongson_i2s_idma_component;
extern const struct snd_soc_component_driver loongson_i2s_edma_component;
extern const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config;
#endif

View File

@ -19,6 +19,7 @@
#include <sound/soc.h>
#include "loongson_i2s.h"
#include "loongson_dma.h"
#define LOONGSON_I2S_RX_DMA_OFFSET 21
#define LOONGSON_I2S_TX_DMA_OFFSET 18
@ -29,62 +30,6 @@
#define LOONGSON_DMA3_CONF 0x3
#define LOONGSON_DMA4_CONF 0x4
/* periods_max = PAGE_SIZE / sizeof(struct ls_dma_chan_reg) */
static const struct snd_pcm_hardware loongson_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S20_3LE |
SNDRV_PCM_FMTBIT_S24_LE,
.period_bytes_min = 128,
.period_bytes_max = 128 * 1024,
.periods_min = 1,
.periods_max = 64,
.buffer_bytes_max = 1024 * 1024,
};
static const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = {
.pcm_hardware = &loongson_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.prealloc_buffer_size = 128 * 1024,
};
static int loongson_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (substream->pcm->device & 1) {
runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
}
if (substream->pcm->device & 2)
runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
/*
* For mysterious reasons (and despite what the manual says)
* playback samples are lost if the DMA count is not a multiple
* of the DMA burst size. Let's add a rule to enforce that.
*/
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128);
snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
return 0;
}
static const struct snd_soc_component_driver loongson_i2s_component_driver = {
.name = LS_I2S_DRVNAME,
.open = loongson_pcm_open,
};
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
{
int val;
@ -147,7 +92,7 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
dev_set_name(dev, LS_I2S_DRVNAME);
dev_set_drvdata(dev, i2s);
ret = devm_snd_soc_register_component(dev, &loongson_i2s_component_driver,
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
&loongson_i2s_dai, 1);
if (ret)
return dev_err_probe(dev, ret, "failed to register DAI\n");