Message ID | 1695202370-24678-2-git-send-email-shengjiu.wang@nxp.com |
---|---|
State | New |
Headers | show |
Series | Add audio support in v4l2 framework | expand |
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@nxp.com> > --- > 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;
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); + int (*m2m_check_rate)(u8 dir, u32 rate); + int (*m2m_check_channel)(u8 dir, u32 channels); + + 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;
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@nxp.com> --- 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(+)