On 20/09/2023 11:32, Shengjiu Wang wrote: > ASRC can be used on memory to memory case, define several > functions for m2m usage. > > m2m_start_part_one: first part of the start steps > m2m_start_part_two: second part of the start steps > m2m_stop_part_one: first part of stop steps > m2m_stop_part_two: second part of stop steps, optional > m2m_check_format: check format is supported or not > m2m_calc_out_len: calculate output length according to input length > m2m_get_maxburst: burst size for dma > m2m_pair_suspend: suspend function of pair, optional. > m2m_pair_resume: resume function of pair > get_output_fifo_size: get remaining data size in FIFO > > Signed-off-by: Shengjiu Wang <shengjiu.wang@xxxxxxx> > --- > sound/soc/fsl/fsl_asrc.c | 150 ++++++++++++++++++++++++++++++++ > sound/soc/fsl/fsl_asrc.h | 2 + > sound/soc/fsl/fsl_asrc_common.h | 42 +++++++++ > 3 files changed, 194 insertions(+) > > diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c > index b793263291dc..f9d830e0957f 100644 > --- a/sound/soc/fsl/fsl_asrc.c > +++ b/sound/soc/fsl/fsl_asrc.c > @@ -1063,6 +1063,145 @@ static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) > return REG_ASRDx(dir, index); > } > > +/* Get sample numbers in FIFO */ > +static unsigned int fsl_asrc_get_output_fifo_size(struct fsl_asrc_pair *pair) > +{ > + struct fsl_asrc *asrc = pair->asrc; > + enum asrc_pair_index index = pair->index; > + u32 val; > + > + regmap_read(asrc->regmap, REG_ASRFST(index), &val); > + > + val &= ASRFSTi_OUTPUT_FIFO_MASK; > + > + return val >> ASRFSTi_OUTPUT_FIFO_SHIFT; > +} > + > +static int fsl_asrc_m2m_start_part_one(struct fsl_asrc_pair *pair) > +{ > + struct fsl_asrc_pair_priv *pair_priv = pair->private; > + struct fsl_asrc *asrc = pair->asrc; > + struct device *dev = &asrc->pdev->dev; > + struct asrc_config config; > + int ret; > + > + /* fill config */ > + config.pair = pair->index; > + config.channel_num = pair->channels; > + config.input_sample_rate = pair->rate[IN]; > + config.output_sample_rate = pair->rate[OUT]; > + config.input_format = pair->sample_format[IN]; > + config.output_format = pair->sample_format[OUT]; > + config.inclk = INCLK_NONE; > + config.outclk = OUTCLK_ASRCK1_CLK; > + > + pair_priv->config = &config; > + ret = fsl_asrc_config_pair(pair, true); > + if (ret) { > + dev_err(dev, "failed to config pair: %d\n", ret); > + return ret; > + } > + > + fsl_asrc_start_pair(pair); > + > + return 0; > +} > + > +static int fsl_asrc_m2m_start_part_two(struct fsl_asrc_pair *pair) > +{ > + /* > + * Clear DMA request during the stall state of ASRC: > + * During STALL state, the remaining in input fifo would never be > + * smaller than the input threshold while the output fifo would not > + * be bigger than output one. Thus the DMA request would be cleared. > + */ > + fsl_asrc_set_watermarks(pair, ASRC_FIFO_THRESHOLD_MIN, > + ASRC_FIFO_THRESHOLD_MAX); > + > + /* Update the real input threshold to raise DMA request */ > + fsl_asrc_set_watermarks(pair, ASRC_M2M_INPUTFIFO_WML, > + ASRC_M2M_OUTPUTFIFO_WML); > + > + return 0; > +} > + > +static int fsl_asrc_m2m_stop_part_one(struct fsl_asrc_pair *pair) > +{ > + fsl_asrc_stop_pair(pair); > + > + return 0; > +} > + > +static int fsl_asrc_m2m_check_format(u8 dir, u32 format) > +{ > + u64 support_format = FSL_ASRC_FORMATS; > + > + if (dir == IN) > + support_format |= SNDRV_PCM_FMTBIT_S8; > + > + if (!(1 << format & support_format)) > + return -EINVAL; > + > + return 0; > +} > + > +static int fsl_asrc_m2m_check_rate(u8 dir, u32 rate) > +{ > + if (rate < 5512 || rate > 192000) > + return -EINVAL; > + > + return 0; > +} > + > +static int fsl_asrc_m2m_check_channel(u8 dir, u32 channels) > +{ > + if (channels < 1 || channels > 10) > + return -EINVAL; > + > + return 0; > +} > + > +/* calculate capture data length according to output data length and sample rate */ > +static int fsl_asrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length) > +{ > + unsigned int in_width, out_width; > + unsigned int channels = pair->channels; > + unsigned int in_samples, out_samples; > + unsigned int out_length; > + > + in_width = snd_pcm_format_physical_width(pair->sample_format[IN]) / 8; > + out_width = snd_pcm_format_physical_width(pair->sample_format[OUT]) / 8; > + > + in_samples = input_buffer_length / in_width / channels; > + out_samples = pair->rate[OUT] * in_samples / pair->rate[IN]; > + out_length = (out_samples - ASRC_OUTPUT_LAST_SAMPLE) * out_width * channels; > + > + return out_length; > +} > + > +static int fsl_asrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair) > +{ > + struct fsl_asrc *asrc = pair->asrc; > + struct fsl_asrc_priv *asrc_priv = asrc->private; > + int wml = (dir == IN) ? ASRC_M2M_INPUTFIFO_WML : ASRC_M2M_OUTPUTFIFO_WML; > + > + if (!asrc_priv->soc->use_edma) > + return wml * pair->channels; > + else > + return 1; > +} > + > +static int fsl_asrc_m2m_pair_resume(struct fsl_asrc_pair *pair) > +{ > + struct fsl_asrc *asrc = pair->asrc; > + int i; > + > + for (i = 0; i < pair->channels * 4; i++) > + regmap_write(asrc->regmap, REG_ASRDI(pair->index), 0); > + > + return 0; > +} > + > static int fsl_asrc_runtime_resume(struct device *dev); > static int fsl_asrc_runtime_suspend(struct device *dev); > > @@ -1147,6 +1286,17 @@ static int fsl_asrc_probe(struct platform_device *pdev) > asrc->get_fifo_addr = fsl_asrc_get_fifo_addr; > asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv); > > + asrc->m2m_start_part_one = fsl_asrc_m2m_start_part_one; > + asrc->m2m_start_part_two = fsl_asrc_m2m_start_part_two; > + asrc->m2m_stop_part_one = fsl_asrc_m2m_stop_part_one; > + asrc->get_output_fifo_size = fsl_asrc_get_output_fifo_size; > + asrc->m2m_check_format = fsl_asrc_m2m_check_format; > + asrc->m2m_check_rate = fsl_asrc_m2m_check_rate; > + asrc->m2m_check_channel = fsl_asrc_m2m_check_channel; > + asrc->m2m_calc_out_len = fsl_asrc_m2m_calc_out_len; > + asrc->m2m_get_maxburst = fsl_asrc_m2m_get_maxburst; > + asrc->m2m_pair_resume = fsl_asrc_m2m_pair_resume; > + > if (of_device_is_compatible(np, "fsl,imx35-asrc")) { > asrc_priv->clk_map[IN] = input_clk_map_imx35; > asrc_priv->clk_map[OUT] = output_clk_map_imx35; > diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h > index 86d2422ad606..1c492eb237f5 100644 > --- a/sound/soc/fsl/fsl_asrc.h > +++ b/sound/soc/fsl/fsl_asrc.h > @@ -12,6 +12,8 @@ > > #include "fsl_asrc_common.h" > > +#define ASRC_M2M_INPUTFIFO_WML 0x4 > +#define ASRC_M2M_OUTPUTFIFO_WML 0x2 > #define ASRC_DMA_BUFFER_NUM 2 > #define ASRC_INPUTFIFO_THRESHOLD 32 > #define ASRC_OUTPUTFIFO_THRESHOLD 32 > diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h > index 7e1c13ca37f1..7f7e725075fe 100644 > --- a/sound/soc/fsl/fsl_asrc_common.h > +++ b/sound/soc/fsl/fsl_asrc_common.h > @@ -34,6 +34,11 @@ enum asrc_pair_index { > * @pos: hardware pointer position > * @req_dma_chan: flag to release dev_to_dev chan > * @private: pair private area > + * @complete: dma task complete > + * @sample_format: format of m2m > + * @rate: rate of m2m > + * @buf_len: buffer length of m2m > + * @req_pair: flag for request pair > */ > struct fsl_asrc_pair { > struct fsl_asrc *asrc; > @@ -49,6 +54,13 @@ struct fsl_asrc_pair { > bool req_dma_chan; > > void *private; > + > + /* used for m2m */ > + struct completion complete[2]; > + snd_pcm_format_t sample_format[2]; > + unsigned int rate[2]; > + unsigned int buf_len[2]; > + bool req_pair; > }; > > /** > @@ -72,6 +84,19 @@ struct fsl_asrc_pair { > * @request_pair: function pointer > * @release_pair: function pointer > * @get_fifo_addr: function pointer > + * @m2m_start_part_one: function pointer > + * @m2m_start_part_two: function pointer > + * @m2m_stop_part_one: function pointer > + * @m2m_stop_part_two: function pointer > + * @m2m_check_format: function pointer > + * @m2m_check_rate: function pointer > + * @m2m_check_channel: function pointer > + * @m2m_calc_out_len: function pointer > + * @m2m_get_maxburst: function pointer > + * @m2m_pair_suspend: function pointer > + * @m2m_pair_resume: function pointer > + * @m2m_set_ratio_mod: function pointer > + * @get_output_fifo_size: function pointer > * @pair_priv_size: size of pair private struct. > * @private: private data structure > */ > @@ -97,6 +122,23 @@ struct fsl_asrc { > int (*request_pair)(int channels, struct fsl_asrc_pair *pair); > void (*release_pair)(struct fsl_asrc_pair *pair); > int (*get_fifo_addr)(u8 dir, enum asrc_pair_index index); > + > + int (*m2m_start_part_one)(struct fsl_asrc_pair *pair); > + int (*m2m_start_part_two)(struct fsl_asrc_pair *pair); > + int (*m2m_stop_part_one)(struct fsl_asrc_pair *pair); > + int (*m2m_stop_part_two)(struct fsl_asrc_pair *pair); > + > + int (*m2m_check_format)(u8 dir, u32 format); I think it will be easier if this just returns the u64 with the supported formats for the given direction. That will be helpful for enum_fmt. > + int (*m2m_check_rate)(u8 dir, u32 rate); This should just map the rate to something that is valid. V4L2 allows drivers to modify the requested format to whatever is valid, and that can be used here. > + int (*m2m_check_channel)(u8 dir, u32 channels); This can do the same (i.e., map to a valid number of channels). Regards, Hans > + > + int (*m2m_calc_out_len)(struct fsl_asrc_pair *pair, int input_buffer_length); > + int (*m2m_get_maxburst)(u8 dir, struct fsl_asrc_pair *pair); > + int (*m2m_pair_suspend)(struct fsl_asrc_pair *pair); > + int (*m2m_pair_resume)(struct fsl_asrc_pair *pair); > + int (*m2m_set_ratio_mod)(struct fsl_asrc_pair *pair, int val); > + > + unsigned int (*get_output_fifo_size)(struct fsl_asrc_pair *pair); > size_t pair_priv_size; > > void *private;