On Mon, Sep 09, 2019 at 06:33:21PM -0400, Shengjiu Wang wrote: > There is error "aplay: pcm_write:2023: write error: Input/output error" > on i.MX8QM/i.MX8QXP platform for S24_3LE format. > > In i.MX8QM/i.MX8QXP, the DMA is EDMA, which don't support 24bit > sample, but we didn't add any constraint, that cause issues. > > So we need to query the caps of dma, then update the hw parameters > according to the caps. > @@ -285,8 +293,81 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) > > runtime->private_data = pair; > > - snd_pcm_hw_constraint_integer(substream->runtime, > - SNDRV_PCM_HW_PARAM_PERIODS); > + ret = snd_pcm_hw_constraint_integer(substream->runtime, > + SNDRV_PCM_HW_PARAM_PERIODS); > + if (ret < 0) { > + dev_err(dev, "failed to set pcm hw params periods\n"); > + return ret; > + } > + > + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); > + > + /* Request a temp pair, which is release in the end */ > + fsl_asrc_request_pair(1, pair); Not sure if it'd be practical, but a pair request could fail. Will probably need to check return value. And a quick feeling is that below code is mostly identical to what is in the soc-generic-dmaengine-pcm.c file. So I'm wondering if we could abstract a helper function somewhere in the ASoC core: Mark? Thanks Nicolin > + tmp_chan = fsl_asrc_get_dma_channel(pair, dir); > + if (!tmp_chan) { > + dev_err(dev, "can't get dma channel\n"); > + return -EINVAL; > + } > + > + ret = dma_get_slave_caps(tmp_chan, &dma_caps); > + if (ret == 0) { > + if (dma_caps.cmd_pause) > + snd_imx_hardware.info |= SNDRV_PCM_INFO_PAUSE | > + SNDRV_PCM_INFO_RESUME; > + if (dma_caps.residue_granularity <= > + DMA_RESIDUE_GRANULARITY_SEGMENT) > + snd_imx_hardware.info |= SNDRV_PCM_INFO_BATCH; > + > + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) > + addr_widths = dma_caps.dst_addr_widths; > + else > + addr_widths = dma_caps.src_addr_widths; > + } > + > + /* > + * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep > + * hw.formats set to 0, meaning no restrictions are in place. > + * In this case it's the responsibility of the DAI driver to > + * provide the supported format information. > + */ > + if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) > + /* > + * Prepare formats mask for valid/allowed sample types. If the > + * dma does not have support for the given physical word size, > + * it needs to be masked out so user space can not use the > + * format which produces corrupted audio. > + * In case the dma driver does not implement the slave_caps the > + * default assumption is that it supports 1, 2 and 4 bytes > + * widths. > + */ > + for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { > + int bits = snd_pcm_format_physical_width(i); > + > + /* > + * Enable only samples with DMA supported physical > + * widths > + */ > + switch (bits) { > + case 8: > + case 16: > + case 24: > + case 32: > + case 64: > + if (addr_widths & (1 << (bits / 8))) > + snd_imx_hardware.formats |= (1LL << i); > + break; > + default: > + /* Unsupported types */ > + break; > + } > + } > + > + if (tmp_chan) > + dma_release_channel(tmp_chan); > + fsl_asrc_release_pair(pair); > + > snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); > > return 0; > -- > 2.21.0 > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx https://mailman.alsa-project.org/mailman/listinfo/alsa-devel