Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: fsl_asrc_m2m: Add option to start ASRC before DMA device for M2M

There is a limitation on i.MX952 that dma request is not cleared at the
end of conversion with dma slave mode. Which causes sample is dropped
from the input fifo on the second time if dma is triggered before the
client device and EDMA may copy wrong data from output fifo as the output
fifo is not ready in the beginning.

The solution is to trigger asrc before dma on i.MX952, and add delay to
wait output data is generated then start the EDMA for output, otherwise
the m2m function has noise issues.

So add an option to start ASRC first for M2M before ASRC is enabled on
i.MX952.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260206014805.3897764-3-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Shengjiu Wang and committed by
Mark Brown
83447a38 37bb773b

+37 -1
+22
sound/soc/fsl/fsl_asrc.c
··· 1078 1078 return val >> ASRFSTi_OUTPUT_FIFO_SHIFT; 1079 1079 } 1080 1080 1081 + static bool fsl_asrc_m2m_output_ready(struct fsl_asrc_pair *pair) 1082 + { 1083 + struct fsl_asrc *asrc = pair->asrc; 1084 + enum asrc_pair_index index = pair->index; 1085 + u32 val; 1086 + int ret; 1087 + 1088 + /* Check output fifo status if it exceeds the watermark. */ 1089 + ret = regmap_read_poll_timeout(asrc->regmap, REG_ASRFST(index), val, 1090 + (ASRFSTi_OUTPUT_FIFO_FILL(val) >= ASRC_M2M_OUTPUTFIFO_WML), 1091 + 1, 1000); 1092 + 1093 + if (ret) { 1094 + pair_warn("output is not ready\n"); 1095 + return false; 1096 + } 1097 + 1098 + return true; 1099 + } 1100 + 1081 1101 static int fsl_asrc_m2m_prepare(struct fsl_asrc_pair *pair) 1082 1102 { 1083 1103 struct fsl_asrc_pair_priv *pair_priv = pair->private; ··· 1295 1275 1296 1276 asrc_priv->soc = of_device_get_match_data(&pdev->dev); 1297 1277 asrc->use_edma = asrc_priv->soc->use_edma; 1278 + asrc->start_before_dma = asrc_priv->soc->start_before_dma; 1298 1279 asrc->get_dma_channel = fsl_asrc_get_dma_channel; 1299 1280 asrc->request_pair = fsl_asrc_request_pair; 1300 1281 asrc->release_pair = fsl_asrc_release_pair; ··· 1310 1289 asrc->m2m_get_maxburst = fsl_asrc_m2m_get_maxburst; 1311 1290 asrc->m2m_pair_resume = fsl_asrc_m2m_pair_resume; 1312 1291 asrc->m2m_get_cap = fsl_asrc_m2m_get_cap; 1292 + asrc->m2m_output_ready = fsl_asrc_m2m_output_ready; 1313 1293 1314 1294 if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 1315 1295 asrc_priv->clk_map[IN] = input_clk_map_imx35;
+4
sound/soc/fsl/fsl_asrc.h
··· 257 257 #define ASRFSTi_OUTPUT_FIFO_WIDTH 7 258 258 #define ASRFSTi_OUTPUT_FIFO_SHIFT 12 259 259 #define ASRFSTi_OUTPUT_FIFO_MASK (((1 << ASRFSTi_OUTPUT_FIFO_WIDTH) - 1) << ASRFSTi_OUTPUT_FIFO_SHIFT) 260 + #define ASRFSTi_OUTPUT_FIFO_FILL(v) \ 261 + (((v) & ASRFSTi_OUTPUT_FIFO_MASK) >> ASRFSTi_OUTPUT_FIFO_SHIFT) 260 262 #define ASRFSTi_IAEi_SHIFT 11 261 263 #define ASRFSTi_IAEi_MASK (1 << ASRFSTi_IAEi_SHIFT) 262 264 #define ASRFSTi_IAEi (1 << ASRFSTi_IAEi_SHIFT) ··· 434 432 * 435 433 * @use_edma: using edma as dma device or not 436 434 * @channel_bits: width of ASRCNCR register for each pair 435 + * @start_before_dma: start asrc before dma 437 436 */ 438 437 struct fsl_asrc_soc_data { 439 438 bool use_edma; 440 439 unsigned int channel_bits; 440 + bool start_before_dma; 441 441 }; 442 442 443 443 /**
+4
sound/soc/fsl/fsl_asrc_common.h
··· 107 107 * @asrc_rate: default sample rate for ASoC Back-Ends 108 108 * @asrc_format: default sample format for ASoC Back-Ends 109 109 * @use_edma: edma is used 110 + * @start_before_dma: start asrc before dma 110 111 * @get_dma_channel: function pointer 111 112 * @request_pair: function pointer 112 113 * @release_pair: function pointer ··· 117 116 * @m2m_start: function pointer 118 117 * @m2m_unprepare: function pointer 119 118 * @m2m_stop: function pointer 119 + * @m2m_output_ready: function pointer, check output fifo ready or not 120 120 * @m2m_calc_out_len: function pointer 121 121 * @m2m_get_maxburst: function pointer 122 122 * @m2m_pair_suspend: function pointer ··· 145 143 int asrc_rate; 146 144 snd_pcm_format_t asrc_format; 147 145 bool use_edma; 146 + bool start_before_dma; 148 147 149 148 struct dma_chan *(*get_dma_channel)(struct fsl_asrc_pair *pair, bool dir); 150 149 int (*request_pair)(int channels, struct fsl_asrc_pair *pair); ··· 157 154 int (*m2m_start)(struct fsl_asrc_pair *pair); 158 155 int (*m2m_unprepare)(struct fsl_asrc_pair *pair); 159 156 int (*m2m_stop)(struct fsl_asrc_pair *pair); 157 + bool (*m2m_output_ready)(struct fsl_asrc_pair *pair); 160 158 161 159 int (*m2m_calc_out_len)(struct fsl_asrc_pair *pair, int input_buffer_length); 162 160 int (*m2m_get_maxburst)(u8 dir, struct fsl_asrc_pair *pair);
+7 -1
sound/soc/fsl/fsl_asrc_m2m.c
··· 253 253 reinit_completion(&pair->complete[IN]); 254 254 reinit_completion(&pair->complete[OUT]); 255 255 256 + if (asrc->start_before_dma) 257 + asrc->m2m_start(pair); 258 + 256 259 /* Submit DMA request */ 257 260 dmaengine_submit(pair->desc[IN]); 258 261 dma_async_issue_pending(pair->desc[IN]->chan); 259 262 if (out_dma_len > 0) { 263 + if (asrc->start_before_dma && asrc->m2m_output_ready) 264 + asrc->m2m_output_ready(pair); 260 265 dmaengine_submit(pair->desc[OUT]); 261 266 dma_async_issue_pending(pair->desc[OUT]->chan); 262 267 } 263 268 264 - asrc->m2m_start(pair); 269 + if (!asrc->start_before_dma) 270 + asrc->m2m_start(pair); 265 271 266 272 if (!wait_for_completion_interruptible_timeout(&pair->complete[IN], 10 * HZ)) { 267 273 dev_err(dev, "out DMA task timeout\n");