From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 03 Jan 2024 09:43:39 +0000 Subject: [PATCH] update kernel to 5.10.198 --- kernel/sound/soc/rockchip/rockchip_multi_dais_pcm.c | 366 +++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 304 insertions(+), 62 deletions(-) diff --git a/kernel/sound/soc/rockchip/rockchip_multi_dais_pcm.c b/kernel/sound/soc/rockchip/rockchip_multi_dais_pcm.c index 88daa5d..0e8955a 100644 --- a/kernel/sound/soc/rockchip/rockchip_multi_dais_pcm.c +++ b/kernel/sound/soc/rockchip/rockchip_multi_dais_pcm.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-or-later /* * ALSA SoC Audio Layer - Rockchip Multi-DAIS-PCM driver * @@ -16,23 +16,44 @@ #include <sound/soc.h> #include "rockchip_multi_dais.h" +#include "rockchip_dlp.h" -#define MAX_FIFO_SIZE 32 /* max fifo size in frames */ -#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm" +#define I2S_TXFIFOLR 0xc +#define I2S_RXFIFOLR 0x2c +#define SAI_TXFIFOLR 0x1c +#define SAI_RXFIFOLR 0x20 + +/* XFL4 is compatible for old version */ +#define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24) +#define I2S_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) +#define I2S_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) +#define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) +#define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) + +/* XFIFOLR: Transfer / Receive FIFO Level Register */ +#define SAI_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18) +#define SAI_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12) +#define SAI_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6) +#define SAI_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0) + +#define MAX_FIFO_SIZE 32 /* max fifo size in frames */ +#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm" static unsigned int prealloc_buffer_size_kbytes = 512; module_param(prealloc_buffer_size_kbytes, uint, 0444); MODULE_PARM_DESC(prealloc_buffer_size_kbytes, "Preallocate DMA buffer size (KB)."); struct dmaengine_mpcm { + struct dlp dlp; struct rk_mdais_dev *mdais; struct dma_chan *tx_chans[MAX_DAIS]; struct dma_chan *rx_chans[MAX_DAIS]; - struct snd_soc_component component; }; struct dmaengine_mpcm_runtime_data { + struct dlp_runtime_data drd; struct dma_chan *chans[MAX_DAIS]; + struct dma_interleaved_template *xt; dma_cookie_t cookies[MAX_DAIS]; unsigned int *channel_maps; int num_chans; @@ -48,12 +69,17 @@ static inline struct dmaengine_mpcm_runtime_data *substream_to_prtd( const struct snd_pcm_substream *substream) { - return substream->runtime->private_data; + struct dlp_runtime_data *drd = substream_to_drd(substream); + + if (!drd) + return NULL; + + return container_of(drd, struct dmaengine_mpcm_runtime_data, drd); } static struct dmaengine_mpcm *soc_component_to_mpcm(struct snd_soc_component *p) { - return container_of(p, struct dmaengine_mpcm, component); + return container_of(soc_component_to_dlp(p), struct dmaengine_mpcm, dlp); } static struct dma_chan *to_chan(struct dmaengine_mpcm *pcm, @@ -105,7 +131,20 @@ { struct snd_pcm_substream *substream = arg; #ifdef CONFIG_SND_SOC_ROCKCHIP_VAD - struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); + struct dmaengine_mpcm_runtime_data *prtd; +#endif + struct dlp_runtime_data *drd; + struct dlp *dlp; + + snd_pcm_stream_lock_irq(substream); + if (!substream->runtime) { + snd_pcm_stream_unlock_irq(substream); + return; + } +#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD + prtd = substream_to_prtd(substream); + if (unlikely(!prtd)) + return; if (snd_pcm_vad_attached(substream) && substream->stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -120,12 +159,21 @@ prtd->pos = 0; #endif + drd = substream_to_drd(substream); + dlp = drd->parent; + + dlp_dma_complete(dlp, drd); + snd_pcm_stream_unlock_irq(substream); + snd_pcm_period_elapsed(substream); } static void dmaengine_mpcm_get_master_chan(struct dmaengine_mpcm_runtime_data *prtd) { int i; + + if (unlikely(!prtd)) + return; for (i = prtd->num_chans; i > 0; i--) { if (prtd->chans[i - 1]) { @@ -135,33 +183,76 @@ } } +static int dmaengine_config_interleaved(struct snd_pcm_substream *substream, + struct dma_interleaved_template *xt, + int offset, int sample_bytes, int nump, int numf) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int frame_bytes; + + frame_bytes = frames_to_bytes(runtime, 1); + + xt->frame_size = 1; + xt->sgl[0].size = sample_bytes; + xt->sgl[0].icg = frame_bytes - sample_bytes; + +#ifdef CONFIG_NO_GKI + xt->nump = nump; +#endif + xt->numf = numf; + + xt->dir = snd_pcm_substream_to_dma_direction(substream); + + if (xt->dir == DMA_MEM_TO_DEV) { + xt->src_start = runtime->dma_addr + offset; + xt->src_inc = true; + xt->src_sgl = true; + xt->dst_inc = false; + xt->dst_sgl = false; + } else { + xt->dst_start = runtime->dma_addr + offset; + xt->src_inc = false; + xt->src_sgl = false; + xt->dst_inc = true; + xt->dst_sgl = true; + } + + return 0; +} + static int dmaengine_mpcm_prepare_and_submit(struct snd_pcm_substream *substream) { struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct dma_async_tx_descriptor *desc = NULL; - enum dma_transfer_direction direction; + struct dma_interleaved_template *xt; unsigned long flags = DMA_CTRL_ACK; - unsigned int *maps = prtd->channel_maps; - int offset, buffer_bytes, period_bytes; + unsigned int *maps; + int offset; int i; - direction = snd_pcm_substream_to_dma_direction(substream); + if (unlikely(!prtd || !runtime)) + return -EINVAL; if (!substream->runtime->no_period_wakeup) flags |= DMA_PREP_INTERRUPT; prtd->pos = 0; offset = 0; - period_bytes = snd_pcm_lib_period_bytes(substream); - buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + + xt = prtd->xt; + maps = prtd->channel_maps; for (i = 0; i < prtd->num_chans; i++) { if (!prtd->chans[i]) continue; - desc = dmaengine_prep_dma_cyclic(prtd->chans[i], - runtime->dma_addr + offset, - buffer_bytes, period_bytes, - direction, flags); + + dmaengine_config_interleaved(substream, xt, offset, + samples_to_bytes(runtime, maps[i]), + runtime->period_size, + runtime->buffer_size); + + desc = dmaengine_prep_interleaved_dma(prtd->chans[i], xt, + flags | DMA_PREP_REPEAT); if (!desc) return -ENOMEM; @@ -185,6 +276,9 @@ { int i; + if (unlikely(!prtd)) + return; + for (i = 0; i < prtd->num_chans; i++) { if (prtd->chans[i]) dma_async_issue_pending(prtd->chans[i]); @@ -194,6 +288,9 @@ static void mpcm_dmaengine_resume(struct dmaengine_mpcm_runtime_data *prtd) { int i; + + if (unlikely(!prtd)) + return; for (i = 0; i < prtd->num_chans; i++) { if (prtd->chans[i]) @@ -205,6 +302,9 @@ { int i; + if (unlikely(!prtd)) + return; + for (i = 0; i < prtd->num_chans; i++) { if (prtd->chans[i]) dmaengine_pause(prtd->chans[i]); @@ -214,6 +314,9 @@ static void mpcm_dmaengine_terminate_all(struct dmaengine_mpcm_runtime_data *prtd) { int i; + + if (unlikely(!prtd)) + return; for (i = 0; i < prtd->num_chans; i++) { if (prtd->chans[i]) @@ -228,6 +331,9 @@ struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); unsigned int pos, size; void *buf; + + if (unlikely(!prtd)) + return; if (snd_pcm_vad_attached(substream) && substream->stream == SNDRV_PCM_STREAM_CAPTURE) { @@ -249,33 +355,39 @@ } static int __mpcm_prepare_single_and_submit(struct snd_pcm_substream *substream, - dma_addr_t buf_start, int size) + int buf_offset, int size) { struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_interleaved_template *xt; struct snd_pcm_runtime *runtime = substream->runtime; struct dma_async_tx_descriptor *desc; - enum dma_transfer_direction direction; unsigned long flags = DMA_CTRL_ACK; - unsigned int *maps = prtd->channel_maps; + unsigned int *maps; int offset, i; bool callback = false; - direction = snd_pcm_substream_to_dma_direction(substream); + if (unlikely(!prtd || !runtime)) + return -EINVAL; if (!substream->runtime->no_period_wakeup) flags |= DMA_PREP_INTERRUPT; - offset = 0; + offset = buf_offset; + xt = prtd->xt; + maps = prtd->channel_maps; for (i = 0; i < prtd->num_chans; i++) { if (!prtd->chans[i]) continue; - desc = dmaengine_prep_slave_single(prtd->chans[i], - buf_start + offset, - size, - direction, flags); + dmaengine_config_interleaved(substream, xt, offset, + samples_to_bytes(runtime, maps[i]), + 0, + bytes_to_frames(runtime, size)); + + desc = dmaengine_prep_interleaved_dma(prtd->chans[i], xt, flags); if (!desc) return -ENOMEM; + if (!callback) { desc->callback = dmaengine_mpcm_single_dma_complete; desc->callback_param = substream; @@ -298,6 +410,9 @@ int offset, i, count, ret; int buffer_bytes, period_bytes, residue_bytes; + if (unlikely(!prtd)) + return -EINVAL; + direction = snd_pcm_substream_to_dma_direction(substream); if (!substream->runtime->no_period_wakeup) @@ -316,15 +431,15 @@ pr_debug("%s: offset: %d, buffer_bytes: %d\n", __func__, offset, buffer_bytes); pr_debug("%s: count: %d, residue_bytes: %d\n", __func__, count, residue_bytes); for (i = 0; i < count; i++) { - ret = __mpcm_prepare_single_and_submit(substream, buf_start, + ret = __mpcm_prepare_single_and_submit(substream, offset, period_bytes); if (ret) return ret; - buf_start += period_bytes; + offset += period_bytes; } if (residue_bytes) { - ret = __mpcm_prepare_single_and_submit(substream, buf_start, + ret = __mpcm_prepare_single_and_submit(substream, offset, residue_bytes); if (ret) return ret; @@ -334,12 +449,50 @@ } #endif -static int snd_dmaengine_mpcm_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int cmd) +static snd_pcm_uframes_t dmaengine_mpcm_raw_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_tx_state state; + unsigned int buf_size; + unsigned int pos = 0; + unsigned int master; + + if (unlikely(!prtd)) + return 0; + + master = prtd->master_chan; + buf_size = snd_pcm_lib_buffer_bytes(substream); + dmaengine_tx_status(prtd->chans[master], prtd->cookies[master], &state); + if (state.residue > 0 && state.residue <= buf_size) + pos = buf_size - state.residue; + + return bytes_to_frames(substream->runtime, pos); +} + +static int dmaengine_mpcm_dlp_start(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); + + return dlp_start(component, substream, pcm->mdais->dev, dmaengine_mpcm_raw_pointer); +} + +static void dmaengine_mpcm_dlp_stop(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + dlp_stop(component, substream, dmaengine_mpcm_raw_pointer); +} + +static int dmaengine_mpcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) { struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; int ret; + + if (unlikely(!prtd || !runtime)) + return -EINVAL; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -355,16 +508,19 @@ if (ret) return ret; mpcm_dma_async_issue_pending(prtd); + dmaengine_mpcm_dlp_start(component, substream); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mpcm_dmaengine_resume(prtd); break; case SNDRV_PCM_TRIGGER_SUSPEND: - if (runtime->info & SNDRV_PCM_INFO_PAUSE) + if (runtime->info & SNDRV_PCM_INFO_PAUSE) { mpcm_dmaengine_pause(prtd); - else + } else { + dmaengine_mpcm_dlp_stop(component, substream); mpcm_dmaengine_terminate_all(prtd); + } prtd->start_flag = false; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -372,6 +528,7 @@ prtd->start_flag = false; break; case SNDRV_PCM_TRIGGER_STOP: + dmaengine_mpcm_dlp_stop(component, substream); mpcm_dmaengine_terminate_all(prtd); prtd->start_flag = false; break; @@ -423,22 +580,12 @@ sz = snd_pcm_format_size(format, maps[i]); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { chan = pcm->tx_chans[i]; -#ifdef CONFIG_NO_GKI - if (sz) { - slave_config.src_interlace_size = frame_bytes - sz; - if (slave_config.src_interlace_size) - slave_config.dst_maxburst = sz / slave_config.dst_addr_width; - } -#endif + if (sz && (frame_bytes - sz) > 0) + slave_config.dst_maxburst = sz / slave_config.dst_addr_width; } else { chan = pcm->rx_chans[i]; -#ifdef CONFIG_NO_GKI - if (sz) { - slave_config.dst_interlace_size = frame_bytes - sz; - if (slave_config.dst_interlace_size) - slave_config.src_maxburst = sz / slave_config.src_addr_width; - } -#endif + if (sz && (frame_bytes - sz) > 0) + slave_config.src_maxburst = sz / slave_config.src_addr_width; } if (!chan) continue; @@ -447,6 +594,11 @@ if (ret) return ret; } + + ret = dlp_hw_params(component, substream, params); + if (ret) + return ret; + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); } @@ -467,12 +619,12 @@ int ret; chan = to_chan(pcm, substream); - if (!chan) + if (!chan || !dma_dev) return -EINVAL; memset(&hw, 0, sizeof(hw)); hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED; + SNDRV_PCM_INFO_INTERLEAVED; hw.periods_min = 2; hw.periods_max = UINT_MAX; hw.period_bytes_min = 256; @@ -542,6 +694,13 @@ if (!prtd) return -ENOMEM; + prtd->xt = kzalloc(sizeof(struct dma_interleaved_template) + + sizeof(struct data_chunk), GFP_KERNEL); + if (!prtd->xt) { + kfree(prtd); + return -ENOMEM; + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { prtd->channel_maps = pcm->mdais->playback_channel_maps; for (i = 0; i < pcm->mdais->num_dais; i++) @@ -554,7 +713,8 @@ prtd->num_chans = pcm->mdais->num_dais; prtd->start_flag = false; - substream->runtime->private_data = prtd; + + dlp_open(&pcm->dlp, &prtd->drd, substream); return 0; } @@ -563,6 +723,7 @@ { struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); struct snd_pcm_substream *substream; + struct device *dma_dev; size_t prealloc_buffer_size; size_t max_buffer_size; unsigned int i; @@ -575,9 +736,15 @@ if (!substream) continue; + dma_dev = dmaengine_dma_dev(pcm, substream); + if (!dma_dev) { + dev_err(component->dev, "No chan found, should assign 'rockchip,no-dmaengine' in DT\n"); + return -EINVAL; + } + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_IRAM, - dmaengine_dma_dev(pcm, substream), + dma_dev, prealloc_buffer_size, max_buffer_size); } @@ -594,8 +761,12 @@ snd_pcm_uframes_t frames; unsigned int buf_size; unsigned int pos = 0; - unsigned int master = prtd->master_chan; + unsigned int master; + if (unlikely(!prtd || !runtime)) + return 0; + + master = prtd->master_chan; buf_size = snd_pcm_lib_buffer_bytes(substream); dmaengine_tx_status(prtd->chans[master], prtd->cookies[master], &state); if (state.residue > 0 && state.residue <= buf_size) @@ -640,24 +811,54 @@ static int dmaengine_mpcm_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + struct dmaengine_mpcm *pcm = soc_component_to_mpcm(component); struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); + if (unlikely(!prtd)) + return -EINVAL; + + dlp_close(&pcm->dlp, &prtd->drd, substream); + + kfree(prtd->xt); kfree(prtd); return 0; } +static int dmaengine_mpcm_copy_user(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + void __user *buf, unsigned long bytes) +{ + return dlp_copy_user(component, substream, channel, hwoff, buf, bytes); +} + + +static int dmaengine_mpcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return dlp_prepare(component, substream); +} + +static int dmaengine_mpcm_probe(struct snd_soc_component *component) +{ + return dlp_probe(component); +} + static const struct snd_soc_component_driver dmaengine_mpcm_platform = { .name = SND_DMAENGINE_MPCM_DRV_NAME, .probe_order = SND_SOC_COMP_ORDER_LATE, + .probe = dmaengine_mpcm_probe, .pcm_construct = dmaengine_mpcm_new, .open = dmaengine_mpcm_open, .close = dmaengine_mpcm_close, .ioctl = dmaengine_mpcm_ioctl, .hw_params = dmaengine_mpcm_hw_params, .hw_free = dmaengine_mpcm_hw_free, - .trigger = snd_dmaengine_mpcm_trigger, + .prepare = dmaengine_mpcm_prepare, + .trigger = dmaengine_mpcm_trigger, .pointer = dmaengine_mpcm_pointer, + .copy_user = dmaengine_mpcm_copy_user, }; static void dmaengine_mpcm_release_chan(struct dmaengine_mpcm *pcm) @@ -671,6 +872,55 @@ dma_release_channel(pcm->rx_chans[i]); } } + +static int dmaengine_mpcm_get_fifo_count(struct device *dev, + struct snd_pcm_substream *substream) +{ + struct rk_mdais_dev *mdais = dev_get_drvdata(dev); + struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream); + struct snd_soc_component *component; + unsigned int tx, rx, reg; + int val = 0; + + if (unlikely(!prtd)) + return -EINVAL; + + component = mdais->dais[prtd->master_chan].dai->component; + if (unlikely(!component)) + return -EINVAL; + + if (strstr(dev_driver_string(component->dev), "i2s")) { + /* compatible for both I2S and I2STDM controller */ + tx = snd_soc_component_read(component, I2S_TXFIFOLR); + rx = snd_soc_component_read(component, I2S_RXFIFOLR); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val = I2S_FIFOLR_XFL3(tx) + + I2S_FIFOLR_XFL2(tx) + + I2S_FIFOLR_XFL1(tx) + + I2S_FIFOLR_XFL0(tx); + else + /* XFL4 is compatible for old version */ + val = I2S_FIFOLR_XFL4(tx) + + I2S_FIFOLR_XFL3(rx) + + I2S_FIFOLR_XFL2(rx) + + I2S_FIFOLR_XFL1(rx) + + I2S_FIFOLR_XFL0(rx); + } else if (strstr(dev_driver_string(component->dev), "sai")) { + reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR; + + val = SAI_FIFOLR_XFL3(reg) + + SAI_FIFOLR_XFL2(reg) + + SAI_FIFOLR_XFL1(reg) + + SAI_FIFOLR_XFL0(reg); + } + + return val; +} + +static const struct snd_dlp_config dconfig = { + .get_fifo_count = dmaengine_mpcm_get_fifo_count, +}; int snd_dmaengine_mpcm_register(struct rk_mdais_dev *mdais) { @@ -689,9 +939,6 @@ if (!pcm) return -ENOMEM; -#ifdef CONFIG_DEBUG_FS - pcm->component.debugfs_prefix = "dma"; -#endif pcm->mdais = mdais; for (i = 0; i < num; i++) { child = mdais->dais[i].dev; @@ -710,12 +957,7 @@ } } - ret = snd_soc_component_initialize(&pcm->component, &dmaengine_mpcm_platform, - dev); - if (ret) - goto err_free_dma; - - ret = snd_soc_add_component(&pcm->component, NULL, 0); + ret = dlp_register(&pcm->dlp, dev, &dmaengine_mpcm_platform, &dconfig); if (ret) goto err_free_dma; -- Gitblit v1.6.2