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;