Skip to content

Commit

Permalink
ASoC: fsl_easrc: define functions for memory to memory usage
Browse files Browse the repository at this point in the history
ASRC can be used on memory to memory case, define several
functions for m2m usage and export them as function pointer.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Link: https://patch.msgid.link/20241212074509.3445859-4-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Shengjiu Wang authored and Mark Brown committed Dec 13, 2024
1 parent 8ea7d04 commit 2714769
Show file tree
Hide file tree
Showing 2 changed files with 232 additions and 0 deletions.
228 changes: 228 additions & 0 deletions sound/soc/fsl/fsl_easrc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1861,6 +1861,224 @@ static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
return REG_EASRC_FIFO(dir, index);
}

/* Get sample numbers in FIFO */
static unsigned int fsl_easrc_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_EASRC_SFS(index), &val);
val &= EASRC_SFS_NSGO_MASK;

return val >> EASRC_SFS_NSGO_SHIFT;
}

static int fsl_easrc_m2m_prepare(struct fsl_asrc_pair *pair)
{
struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
struct fsl_asrc *asrc = pair->asrc;
struct device *dev = &asrc->pdev->dev;
int ret;

ctx_priv->in_params.sample_rate = pair->rate[IN];
ctx_priv->in_params.sample_format = pair->sample_format[IN];
ctx_priv->out_params.sample_rate = pair->rate[OUT];
ctx_priv->out_params.sample_format = pair->sample_format[OUT];

ctx_priv->in_params.fifo_wtmk = FSL_EASRC_INPUTFIFO_WML;
ctx_priv->out_params.fifo_wtmk = FSL_EASRC_OUTPUTFIFO_WML;
/* Fill the right half of the re-sampler with zeros */
ctx_priv->rs_init_mode = 0x2;
/* Zero fill the right half of the prefilter */
ctx_priv->pf_init_mode = 0x2;

ret = fsl_easrc_set_ctx_format(pair,
&ctx_priv->in_params.sample_format,
&ctx_priv->out_params.sample_format);
if (ret) {
dev_err(dev, "failed to set context format: %d\n", ret);
return ret;
}

ret = fsl_easrc_config_context(asrc, pair->index);
if (ret) {
dev_err(dev, "failed to config context %d\n", ret);
return ret;
}

ctx_priv->in_params.iterations = 1;
ctx_priv->in_params.group_len = pair->channels;
ctx_priv->in_params.access_len = pair->channels;
ctx_priv->out_params.iterations = 1;
ctx_priv->out_params.group_len = pair->channels;
ctx_priv->out_params.access_len = pair->channels;

ret = fsl_easrc_set_ctx_organziation(pair);
if (ret) {
dev_err(dev, "failed to set fifo organization\n");
return ret;
}

/* The context start flag */
pair->first_convert = 1;
return 0;
}

static int fsl_easrc_m2m_start(struct fsl_asrc_pair *pair)
{
/* start context once */
if (pair->first_convert) {
fsl_easrc_start_context(pair);
pair->first_convert = 0;
}

return 0;
}

static int fsl_easrc_m2m_stop(struct fsl_asrc_pair *pair)
{
/* Stop pair/context */
if (!pair->first_convert) {
fsl_easrc_stop_context(pair);
pair->first_convert = 1;
}

return 0;
}

/* calculate capture data length according to output data length and sample rate */
static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length)
{
struct fsl_asrc *easrc = pair->asrc;
struct fsl_easrc_priv *easrc_priv = easrc->private;
struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
unsigned int in_rate = ctx_priv->in_params.norm_rate;
unsigned int out_rate = ctx_priv->out_params.norm_rate;
unsigned int channels = pair->channels;
unsigned int in_samples, out_samples;
unsigned int in_width, out_width;
unsigned int out_length;
unsigned int frac_bits;
u64 val1, val2;

switch (easrc_priv->rs_num_taps) {
case EASRC_RS_32_TAPS:
/* integer bits = 5; */
frac_bits = 39;
break;
case EASRC_RS_64_TAPS:
/* integer bits = 6; */
frac_bits = 38;
break;
case EASRC_RS_128_TAPS:
/* integer bits = 7; */
frac_bits = 37;
break;
default:
return -EINVAL;
}

val1 = (u64)in_rate << frac_bits;
do_div(val1, out_rate);
val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31);

in_width = snd_pcm_format_physical_width(ctx_priv->in_params.sample_format) / 8;
out_width = snd_pcm_format_physical_width(ctx_priv->out_params.sample_format) / 8;

ctx_priv->in_filled_len += input_buffer_length;
if (ctx_priv->in_filled_len <= ctx_priv->in_filled_sample * in_width * channels) {
out_length = 0;
} else {
in_samples = ctx_priv->in_filled_len / (in_width * channels) -
ctx_priv->in_filled_sample;

/* right shift 12 bit to make ratio in 32bit space */
val2 = (u64)in_samples << (frac_bits - 12);
val1 = val1 >> 12;
do_div(val2, val1);
out_samples = val2;

out_length = out_samples * out_width * channels;
ctx_priv->in_filled_len = ctx_priv->in_filled_sample * in_width * channels;
}

return out_length;
}

static int fsl_easrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
{
struct fsl_easrc_ctx_priv *ctx_priv = pair->private;

if (dir == IN)
return ctx_priv->in_params.fifo_wtmk * pair->channels;
else
return ctx_priv->out_params.fifo_wtmk * pair->channels;
}

static int fsl_easrc_m2m_pair_suspend(struct fsl_asrc_pair *pair)
{
fsl_easrc_stop_context(pair);

return 0;
}

static int fsl_easrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
{
struct fsl_easrc_ctx_priv *ctx_priv = pair->private;

pair->first_convert = 1;
ctx_priv->in_filled_len = 0;

return 0;
}

/* val is Q31 */
static int fsl_easrc_m2m_set_ratio_mod(struct fsl_asrc_pair *pair, int val)
{
struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
struct fsl_asrc *easrc = pair->asrc;
struct fsl_easrc_priv *easrc_priv = easrc->private;
unsigned int frac_bits;

ctx_priv->ratio_mod += val;

switch (easrc_priv->rs_num_taps) {
case EASRC_RS_32_TAPS:
/* integer bits = 5; */
frac_bits = 39;
break;
case EASRC_RS_64_TAPS:
/* integer bits = 6; */
frac_bits = 38;
break;
case EASRC_RS_128_TAPS:
/* integer bits = 7; */
frac_bits = 37;
break;
default:
return -EINVAL;
}

val <<= (frac_bits - 31);
regmap_write(easrc->regmap, REG_EASRC_RUC(pair->index), EASRC_RSUC_RS_RM(val));

return 0;
}

static int fsl_easrc_m2m_get_cap(struct fsl_asrc_m2m_cap *cap)
{
cap->fmt_in = FSL_EASRC_FORMATS;
cap->fmt_out = FSL_EASRC_FORMATS | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
cap->rate_in = easrc_rates;
cap->rate_in_count = ARRAY_SIZE(easrc_rates);
cap->rate_out = easrc_rates;
cap->rate_out_count = ARRAY_SIZE(easrc_rates);
cap->chan_min = 1;
cap->chan_max = 32;
return 0;
}

static const struct of_device_id fsl_easrc_dt_ids[] = {
{ .compatible = "fsl,imx8mn-easrc",},
{}
Expand Down Expand Up @@ -1926,6 +2144,16 @@ static int fsl_easrc_probe(struct platform_device *pdev)
easrc->release_pair = fsl_easrc_release_context;
easrc->get_fifo_addr = fsl_easrc_get_fifo_addr;
easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv);
easrc->m2m_prepare = fsl_easrc_m2m_prepare;
easrc->m2m_start = fsl_easrc_m2m_start;
easrc->m2m_stop = fsl_easrc_m2m_stop;
easrc->get_output_fifo_size = fsl_easrc_get_output_fifo_size;
easrc->m2m_calc_out_len = fsl_easrc_m2m_calc_out_len;
easrc->m2m_get_maxburst = fsl_easrc_m2m_get_maxburst;
easrc->m2m_pair_suspend = fsl_easrc_m2m_pair_suspend;
easrc->m2m_pair_resume = fsl_easrc_m2m_pair_resume;
easrc->m2m_set_ratio_mod = fsl_easrc_m2m_set_ratio_mod;
easrc->m2m_get_cap = fsl_easrc_m2m_get_cap;

easrc_priv->rs_num_taps = EASRC_RS_32_TAPS;
easrc_priv->const_coeff = 0x3FF0000000000000;
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/fsl/fsl_easrc.h
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,8 @@ struct fsl_easrc_slot {
* @out_missed_sample: sample missed in output
* @st1_addexp: exponent added for stage1
* @st2_addexp: exponent added for stage2
* @ratio_mod: update ratio
* @in_filled_len: input filled length
*/
struct fsl_easrc_ctx_priv {
struct fsl_easrc_io_params in_params;
Expand All @@ -618,6 +620,8 @@ struct fsl_easrc_ctx_priv {
int out_missed_sample;
int st1_addexp;
int st2_addexp;
int ratio_mod;
unsigned int in_filled_len;
};

/**
Expand Down

0 comments on commit 2714769

Please sign in to comment.