[PATCH v5 1/6] ALSA: compress: Add output rate and output format support
Add 'pcm_format' for struct snd_codec, add 'pcm_formats' for struct snd_codec_desc, these are used for accelerator usage. Current accelerator example is sample rate converter (SRC). Define struct snd_codec_desc_src for descript minmum and maxmum sample rates. And add 'src_d' in union snd_codec_options structure. These are mainly used for capbility query. Signed-off-by: Jaroslav Kysela Signed-off-by: Shengjiu Wang Acked-by: Jaroslav Kysela --- include/uapi/sound/compress_params.h | 23 +-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ddc77322d571..bc7648a30746 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -334,6 +334,14 @@ union snd_codec_options { struct snd_dec_wma wma_d; struct snd_dec_alac alac_d; struct snd_dec_ape ape_d; + struct { + __u32 out_sample_rate; + } src_d; +} __attribute__((packed, aligned(4))); + +struct snd_codec_desc_src { + __u32 out_sample_rate_min; + __u32 out_sample_rate_max; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities @@ -347,6 +355,9 @@ union snd_codec_options { * @modes: Supported modes. See SND_AUDIOMODE defines * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines * @min_buffer: Minimum buffer size handled by codec implementation + * @pcm_formats: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) + * @u_space: union space (for codec dependent data) * @reserved: reserved for future use * * This structure provides a scalar value for profiles, modes and stream @@ -370,7 +381,12 @@ struct snd_codec_desc { __u32 modes; __u32 formats; __u32 min_buffer; - __u32 reserved[15]; + __u32 pcm_formats; + union { + __u32 u_space[6]; + struct snd_codec_desc_src src; + } __attribute__((packed, aligned(4))); + __u32 reserved[8]; } __attribute__((packed, aligned(4))); /** struct snd_codec @@ -395,6 +411,8 @@ struct snd_codec_desc { * @align: Block alignment in bytes of an audio sample. * Only required for PCM or IEC formats. * @options: encoder-specific settings + * @pcm_format: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) * @reserved: reserved for future use */ @@ -411,7 +429,8 @@ struct snd_codec { __u32 format; __u32 align; union snd_codec_options options; - __u32 reserved[3]; + __u32 pcm_format; + __u32 reserved[2]; } __attribute__((packed, aligned(4))); #endif -- 2.34.1
[PATCH v5 5/6] ASoC: fsl_asrc: register m2m platform device
Register m2m platform device, that user can use M2M feature. Signed-off-by: Shengjiu Wang Acked-by: Jaroslav Kysela --- sound/soc/fsl/fsl_asrc.c | 37 + 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 471753276209..677529916dc0 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1384,6 +1384,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_get_sync; } + ret = fsl_asrc_m2m_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_get_sync: @@ -1396,6 +1402,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) static void fsl_asrc_remove(struct platform_device *pdev) { + struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(asrc); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) fsl_asrc_runtime_suspend(&pdev->dev); @@ -1497,10 +1507,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(asrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(asrc); + return ret; +} + static const struct dev_pm_ops fsl_asrc_pm = { - SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { @@ -1538,7 +1567,7 @@ static struct platform_driver fsl_asrc_driver = { .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, - .pm = &fsl_asrc_pm, + .pm = pm_ptr(&fsl_asrc_pm), }, }; module_platform_driver(fsl_asrc_driver); -- 2.34.1
[PATCH v5 6/6] ASoC: fsl_easrc: register m2m platform device
Register m2m platform device,that user can use M2M feature. Signed-off-by: Shengjiu Wang Acked-by: Jaroslav Kysela --- sound/soc/fsl/fsl_easrc.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index f17a185a1910..f404a39009e1 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2204,6 +2204,12 @@ static int fsl_easrc_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = fsl_asrc_m2m_init(easrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_disable: @@ -2213,6 +2219,10 @@ static int fsl_easrc_probe(struct platform_device *pdev) static void fsl_easrc_remove(struct platform_device *pdev) { + struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(easrc); + pm_runtime_disable(&pdev->dev); } @@ -2313,10 +2323,29 @@ static int fsl_easrc_runtime_resume(struct device *dev) return ret; } +static int fsl_easrc_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(easrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_easrc_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(easrc); + return ret; +} + static const struct dev_pm_ops fsl_easrc_pm_ops = { RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume) }; static struct platform_driver fsl_easrc_driver = { -- 2.34.1
[PATCH v5 3/6] ASoC: fsl_easrc: define functions for memory to memory usage
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 Acked-by: Jaroslav Kysela --- sound/soc/fsl/fsl_easrc.c | 228 ++ sound/soc/fsl/fsl_easrc.h | 4 + 2 files changed, 232 insertions(+) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index d22f0621c465..f17a185a1910 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -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_w
[PATCH v5 2/6] ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step 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 Acked-by: Jaroslav Kysela --- sound/soc/fsl/fsl_asrc.c| 142 sound/soc/fsl/fsl_asrc.h| 2 + sound/soc/fsl/fsl_asrc_common.h | 61 ++ 3 files changed, 205 insertions(+) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index bd5c46d763c0..471753276209 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1063,6 +1063,139 @@ 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_prepare(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; + } + + pair->first_convert = 1; + + return 0; +} + +static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair) +{ + if (pair->first_convert) { + fsl_asrc_start_pair(pair); + pair->first_convert = 0; + } + /* +* 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(struct fsl_asrc_pair *pair) +{ + if (!pair->first_convert) { + fsl_asrc_stop_pair(pair); + pair->first_convert = 1; + } + + 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_get_cap(struct fsl_asrc_m2m_cap *cap) +{ + cap->fmt_in = FSL_ASRC_FORMATS; + cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8; + + cap->rate_in = supported_asrc_rate; + cap->rat
[PATCH v5 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
Implement the ASRC memory to memory function using the compress framework, user can use this function with compress ioctl interface. This feature can be shared by ASRC and EASRC drivers Signed-off-by: Shengjiu Wang Acked-by: Jaroslav Kysela --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc_common.h | 9 + sound/soc/fsl/fsl_asrc_m2m.c| 727 4 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..bff9c6bda344 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -8,6 +8,7 @@ config SND_SOC_FSL_ASRC depends on HAS_DMA select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_COMPRESS_ACCEL help Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) support for the Freescale CPUs. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ad97244b5cc3..d656a9ab54e3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o -snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 3bdd6ea07c09..0cd595b0f629 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -60,6 +60,7 @@ struct fsl_asrc_m2m_cap { * @buf_len: buffer length of m2m * @dma_buffer: buffer pointers * @first_convert: start of conversion + * @ratio_mod_flag: flag for new ratio modifier * @ratio_mod: ratio modification */ struct fsl_asrc_pair { @@ -84,6 +85,7 @@ struct fsl_asrc_pair { unsigned int buf_len[2]; struct snd_dma_buffer dma_buffer[2]; unsigned int first_convert; + bool ratio_mod_flag; unsigned int ratio_mod; }; @@ -98,6 +100,7 @@ struct fsl_asrc_pair { * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral * @spba_clk: SPBA clock (optional, depending on SoC design) + * @card: compress sound card * @lock: spin lock for resource protection * @pair: pair pointers * @channel_avail: non-occupied channel numbers @@ -131,6 +134,7 @@ struct fsl_asrc { struct clk *mem_clk; struct clk *ipg_clk; struct clk *spba_clk; + struct snd_card *card; spinlock_t lock; /* spin lock for resource protection */ struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; @@ -166,4 +170,9 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; +int fsl_asrc_m2m_init(struct fsl_asrc *asrc); +void fsl_asrc_m2m_exit(struct fsl_asrc *asrc); +int fsl_asrc_m2m_resume(struct fsl_asrc *asrc); +int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc); + #endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c new file mode 100644 index ..693ec0a477a4 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +// Copyright (C) 2019-2024 NXP +// +// Freescale ASRC Memory to Memory (M2M) driver + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_asrc_common.h" + +#define DIR_STR(dir) (dir) == IN ? "in" : "out" + +#define ASRC_xPUT_DMA_CALLBACK(dir) \ + (((dir) == IN) ? asrc_input_dma_callback \ + : asrc_output_dma_callback) + +/* Maximum output and capture buffer size */ +#define ASRC_M2M_BUFFER_SIZE (512 * 1024) + +/* Maximum output and capture period size */ +#define ASRC_M2M_PERIOD_SIZE (48 * 1024) + +/* dma complete callback */ +static void asrc_input_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[IN]); +} + +/* dma complete callback */ +static void asrc_output_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[OUT]); +} + +/** + *asrc_read_last_fifo: read all the remaining data from FIFO + *@pair: Structure pointer of fsl_asrc_pair + *@dma_vaddr: virtual address of capture buffer + *@length: payload length of capture buffer + */ +static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, void *dma_vaddr, u32 *length) +{ + struct fsl_asrc *asrc = pair->asrc; + enum asrc_pair_index index = pair->index; + u32 i, reg, size, t_size = 0,
[PATCH v5 0/6] ASoC: fsl: add memory to memory function for ASRC
This function is base on the accelerator implementation for compress API: https://patchwork.kernel.org/project/alsa-devel/patch/20241002093904.1809799-1-pe...@perex.cz/ Audio signal processing also has the requirement for memory to memory similar as Video. This asrc memory to memory (memory ->asrc->memory) case is a non real time use case. User fills the input buffer to the asrc module, after conversion, then asrc sends back the output buffer to user. So it is not a traditional ALSA playback and capture case. Because we had implemented the "memory -> asrc ->i2s device-> codec" use case in ALSA. Now the "memory->asrc->memory" needs to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining the code to make it can be shared by the "memory->asrc->memory" driver. Other change is to add memory to memory support for two kinds of i.MX ASRC modules. changes in v5: - Drop Jaroslav Kysela's patch as it has been merged. - Add Jaroslav Kysela's Acked-by tag, received in v3. changes in v4: - remove the RFC tag, no comments receive in v3 - Add Jaroslav Kysela's patch in this patch set. because it may be better for reviewing in a full patch set. - Fix the list_for_each_entry_reverse to list_for_each_entry_safe_reverse - Fix some coding style issues in Jaroslav Kysela's patch changes in v3: - use Jaroslav's suggestion for header file compress_params.h (PATCH 01) - remove the ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE definition - remove ASRC_RATIO_MOD in this version because it uses .set_metadata() Will wait Jaroslav's update or other better method in the future. - Address some comments from Pierre. changes in v2: - Remove the changes in compress API - drop the SNDRV_COMPRESS_SRC_RATIO_MOD - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src - define private metadata key value ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD Shengjiu Wang (6): ALSA: compress: Add output rate and output format support ASoC: fsl_asrc: define functions for memory to memory usage ASoC: fsl_easrc: define functions for memory to memory usage ASoC: fsl_asrc_m2m: Add memory to memory function ASoC: fsl_asrc: register m2m platform device ASoC: fsl_easrc: register m2m platform device include/uapi/sound/compress_params.h | 23 +- sound/soc/fsl/Kconfig| 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc.c | 179 ++- sound/soc/fsl/fsl_asrc.h | 2 + sound/soc/fsl/fsl_asrc_common.h | 70 +++ sound/soc/fsl/fsl_asrc_m2m.c | 727 +++ sound/soc/fsl/fsl_easrc.c| 261 +- sound/soc/fsl/fsl_easrc.h| 4 + 9 files changed, 1260 insertions(+), 9 deletions(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c -- 2.34.1
[PATCH v2] ASoC: fsl_mqs: Support accessing registers by scmi interface
On i.MX95, the MQS module in Always-on (AON) domain only can be accessed by System Controller Management Interface (SCMI) MISC Protocol. So define a specific regmap_config for the case. Signed-off-by: Shengjiu Wang --- changes in v2: - fix compile issue when IMX_SCMI_MISC_DRV=m but SND_SOC_FSL_MQS=y sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/fsl_mqs.c | 41 + 2 files changed, 42 insertions(+) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index bff9c6bda344..698afae46918 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -31,6 +31,7 @@ config SND_SOC_FSL_MQS tristate "Medium Quality Sound (MQS) module support" depends on SND_SOC_FSL_SAI select REGMAP_MMIO + select IMX_SCMI_MISC_DRV if IMX_SCMI_MISC_EXT !=n help Say Y if you want to add Medium Quality Sound (MQS) support for the Freescale CPUs. diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 145f9ca15e43..0513e9e8402e 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -6,6 +6,7 @@ // Copyright 2019 NXP #include +#include #include #include #include @@ -74,6 +75,29 @@ struct fsl_mqs { #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) #define FSL_MQS_FORMATSSNDRV_PCM_FMTBIT_S16_LE +static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val) +{ + struct fsl_mqs *mqs_priv = context; + int num = 1; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, &num, val); + + return -EINVAL; +}; + +static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val) +{ + struct fsl_mqs *mqs_priv = context; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, val); + + return -EINVAL; +}; + static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -188,6 +212,13 @@ static const struct regmap_config fsl_mqs_regmap_config = { .cache_type = REGCACHE_NONE, }; +static const struct regmap_config fsl_mqs_sm_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_read = fsl_mqs_sm_read, + .reg_write = fsl_mqs_sm_write, +}; + static int fsl_mqs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -219,6 +250,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get gpr regmap\n"); return PTR_ERR(mqs_priv->regmap); } + } else if (mqs_priv->soc->type == TYPE_REG_SM) { + mqs_priv->regmap = devm_regmap_init(&pdev->dev, + NULL, + mqs_priv, + &fsl_mqs_sm_regmap); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(mqs_priv->regmap)); + return PTR_ERR(mqs_priv->regmap); + } } else { regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) -- 2.34.1
Re: [PATCH] ASoC: fsl_mqs: Support accessing registers by scmi interface
On Sat, Oct 12, 2024 at 2:15 PM Shengjiu Wang wrote: > > On i.MX95, the MQS module in Always-on (AON) domain only can > be accessed by System Controller Management Interface (SCMI) > MISC Protocol. So define a specific regmap_config for the case. > find an issue when IMX_SCMI_MISC_DRV=m but SND_SOC_FSL_MQS=y will send v2 to fix it. Best regards Shengjiu Wang > Signed-off-by: Shengjiu Wang > --- > sound/soc/fsl/fsl_mqs.c | 41 + > 1 file changed, 41 insertions(+) > > diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c > index 145f9ca15e43..0513e9e8402e 100644 > --- a/sound/soc/fsl/fsl_mqs.c > +++ b/sound/soc/fsl/fsl_mqs.c > @@ -6,6 +6,7 @@ > // Copyright 2019 NXP > > #include > +#include > #include > #include > #include > @@ -74,6 +75,29 @@ struct fsl_mqs { > #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) > #define FSL_MQS_FORMATSSNDRV_PCM_FMTBIT_S16_LE > > +static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int > *val) > +{ > + struct fsl_mqs *mqs_priv = context; > + int num = 1; > + > + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && > + mqs_priv->soc->ctrl_off == reg) > + return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, > &num, val); > + > + return -EINVAL; > +}; > + > +static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int > val) > +{ > + struct fsl_mqs *mqs_priv = context; > + > + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && > + mqs_priv->soc->ctrl_off == reg) > + return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, > val); > + > + return -EINVAL; > +}; > + > static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, > struct snd_pcm_hw_params *params, > struct snd_soc_dai *dai) > @@ -188,6 +212,13 @@ static const struct regmap_config fsl_mqs_regmap_config > = { > .cache_type = REGCACHE_NONE, > }; > > +static const struct regmap_config fsl_mqs_sm_regmap = { > + .reg_bits = 32, > + .val_bits = 32, > + .reg_read = fsl_mqs_sm_read, > + .reg_write = fsl_mqs_sm_write, > +}; > + > static int fsl_mqs_probe(struct platform_device *pdev) > { > struct device_node *np = pdev->dev.of_node; > @@ -219,6 +250,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) > dev_err(&pdev->dev, "failed to get gpr regmap\n"); > return PTR_ERR(mqs_priv->regmap); > } > + } else if (mqs_priv->soc->type == TYPE_REG_SM) { > + mqs_priv->regmap = devm_regmap_init(&pdev->dev, > + NULL, > + mqs_priv, > + &fsl_mqs_sm_regmap); > + if (IS_ERR(mqs_priv->regmap)) { > + dev_err(&pdev->dev, "failed to init regmap: %ld\n", > + PTR_ERR(mqs_priv->regmap)); > + return PTR_ERR(mqs_priv->regmap); > + } > } else { > regs = devm_platform_ioremap_resource(pdev, 0); > if (IS_ERR(regs)) > -- > 2.34.1 >
Re: [PATCH v4 0/7] ASoC: fsl: add memory to memory function for ASRC
On Wed, Oct 23, 2024 at 1:32 PM Vinod Koul wrote: > > On 25-09-24, 14:55, Shengjiu Wang wrote: > > This function is base on the accelerator implementation > > for compress API: > > https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ > > Add it to this patch set. > > > > Audio signal processing also has the requirement for memory to > > memory similar as Video. > > > > This asrc memory to memory (memory ->asrc->memory) case is a non > > real time use case. > > > > User fills the input buffer to the asrc module, after conversion, then asrc > > sends back the output buffer to user. So it is not a traditional ALSA > > playback > > and capture case. > > > > Because we had implemented the "memory -> asrc ->i2s device-> codec" > > use case in ALSA. Now the "memory->asrc->memory" needs > > to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining > > the code to make it can be shared by the "memory->asrc->memory" > > driver. > > > > Other change is to add memory to memory support for two kinds of i.MX ASRC > > modules. > > Are there any patches for tinycompress to use the new IOCTLs here, I > would like to see those changes as well Yes, just create a pull request here: https://github.com/alsa-project/tinycompress/pull/26 Best regards Shengjiu Wang > > -- > ~Vinod
[PATCH] ASoC: fsl_micfil: Add sample rate constraint
On some platforms, for example i.MX93, there is only one audio PLL source, so some sample rate can't be supported. If the PLL source is used for 8kHz series rates, then 11kHz series rates can't be supported. So add constraints according to the frequency of available clock sources, then alsa-lib will help to convert the unsupported rate for the driver. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 38 ++ 1 file changed, 38 insertions(+) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 4e65966d54fc..619ee7a5b867 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -28,6 +28,13 @@ #define MICFIL_OSR_DEFAULT 16 +#define MICFIL_NUM_RATES 7 +#define MICFIL_CLK_SRC_NUM 3 +/* clock source ids */ +#define MICFIL_AUDIO_PLL1 0 +#define MICFIL_AUDIO_PLL2 1 +#define MICFIL_CLK_EXT32 + enum quality { QUALITY_HIGH, QUALITY_MEDIUM, @@ -45,9 +52,12 @@ struct fsl_micfil { struct clk *mclk; struct clk *pll8k_clk; struct clk *pll11k_clk; + struct clk *clk_src[MICFIL_CLK_SRC_NUM]; struct snd_dmaengine_dai_dma_data dma_params_rx; struct sdma_peripheral_config sdmacfg; struct snd_soc_card *card; + struct snd_pcm_hw_constraint_list constraint_rates; + unsigned int constraint_rates_list[MICFIL_NUM_RATES]; unsigned int dataline; char name[32]; int irq[MICFIL_IRQ_LINES]; @@ -450,12 +460,34 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + unsigned int rates[MICFIL_NUM_RATES] = {8000, 11025, 16000, 22050, 32000, 44100, 48000}; + int i, j, k = 0; + u64 clk_rate; if (!micfil) { dev_err(dai->dev, "micfil dai priv_data not set\n"); return -EINVAL; } + micfil->constraint_rates.list = micfil->constraint_rates_list; + micfil->constraint_rates.count = 0; + + for (j = 0; j < MICFIL_NUM_RATES; j++) { + for (i = 0; i < MICFIL_CLK_SRC_NUM; i++) { + clk_rate = clk_get_rate(micfil->clk_src[i]); + if (clk_rate != 0 && do_div(clk_rate, rates[j]) == 0) { + micfil->constraint_rates_list[k++] = rates[j]; + micfil->constraint_rates.count++; + break; + } + } + } + + if (micfil->constraint_rates.count > 0) + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &micfil->constraint_rates); + return 0; } @@ -1160,6 +1192,12 @@ static int fsl_micfil_probe(struct platform_device *pdev) fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk, &micfil->pll11k_clk); + micfil->clk_src[MICFIL_AUDIO_PLL1] = micfil->pll8k_clk; + micfil->clk_src[MICFIL_AUDIO_PLL2] = micfil->pll11k_clk; + micfil->clk_src[MICFIL_CLK_EXT3] = devm_clk_get(&pdev->dev, "clkext3"); + if (IS_ERR(micfil->clk_src[MICFIL_CLK_EXT3])) + micfil->clk_src[MICFIL_CLK_EXT3] = NULL; + /* init regmap */ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) -- 2.34.1
[PATCH] ASoC: fsl_mqs: Support accessing registers by scmi interface
On i.MX95, the MQS module in Always-on (AON) domain only can be accessed by System Controller Management Interface (SCMI) MISC Protocol. So define a specific regmap_config for the case. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_mqs.c | 41 + 1 file changed, 41 insertions(+) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 145f9ca15e43..0513e9e8402e 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -6,6 +6,7 @@ // Copyright 2019 NXP #include +#include #include #include #include @@ -74,6 +75,29 @@ struct fsl_mqs { #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) #define FSL_MQS_FORMATSSNDRV_PCM_FMTBIT_S16_LE +static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val) +{ + struct fsl_mqs *mqs_priv = context; + int num = 1; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, &num, val); + + return -EINVAL; +}; + +static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val) +{ + struct fsl_mqs *mqs_priv = context; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, val); + + return -EINVAL; +}; + static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -188,6 +212,13 @@ static const struct regmap_config fsl_mqs_regmap_config = { .cache_type = REGCACHE_NONE, }; +static const struct regmap_config fsl_mqs_sm_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_read = fsl_mqs_sm_read, + .reg_write = fsl_mqs_sm_write, +}; + static int fsl_mqs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -219,6 +250,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get gpr regmap\n"); return PTR_ERR(mqs_priv->regmap); } + } else if (mqs_priv->soc->type == TYPE_REG_SM) { + mqs_priv->regmap = devm_regmap_init(&pdev->dev, + NULL, + mqs_priv, + &fsl_mqs_sm_regmap); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(mqs_priv->regmap)); + return PTR_ERR(mqs_priv->regmap); + } } else { regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) -- 2.34.1
[PATCH] ASoC: fsl_esai: change dev_warn to dev_dbg in irq handler
Irq handler need to be executed as fast as possible, so the log in irq handler is better to use dev_dbg which needs to be enabled when debugging. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_esai.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index a65f5b9935a2..0b247f16a163 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -119,10 +119,10 @@ static irqreturn_t esai_isr(int irq, void *devid) dev_dbg(&pdev->dev, "isr: Transmission Initialized\n"); if (esr & ESAI_ESR_RFF_MASK) - dev_warn(&pdev->dev, "isr: Receiving overrun\n"); + dev_dbg(&pdev->dev, "isr: Receiving overrun\n"); if (esr & ESAI_ESR_TFE_MASK) - dev_warn(&pdev->dev, "isr: Transmission underrun\n"); + dev_dbg(&pdev->dev, "isr: Transmission underrun\n"); if (esr & ESAI_ESR_TLS_MASK) dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n"); -- 2.34.1
[PATCH 1/2] ASoC: imx-card: Set mclk for codec
From: Chancel Liu In some cases, ASoC machine driver may modify the mclk frequency according to sample rate but the value in codec is still initial frequency which should be replaced. For example, we should update mclk before setup for cs42xx8 mclk relating registers. Signed-off-by: Chancel Liu Signed-off-by: Shengjiu Wang --- sound/soc/fsl/imx-card.c | 5 + 1 file changed, 5 insertions(+) diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index a7215bad6484..2f3dbbd15791 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -370,6 +370,11 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); return ret; } + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret); + return ret; + } return 0; } -- 2.34.1
[PATCH 2/2] ASoC: imx-card: Add CS42888 support
From: Chancel Liu CS42888 codec provides 4 multi-bit ADC and 8 multi-bit DAC. Add support for this codec in imx-card ASoC machine driver. Signed-off-by: Chancel Liu Signed-off-by: Shengjiu Wang --- sound/soc/fsl/imx-card.c | 54 ++-- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 2f3dbbd15791..306168b164d3 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -25,6 +25,7 @@ enum codec_type { CODEC_AK4458, CODEC_AK4497, CODEC_AK5552, + CODEC_CS42888, }; /* @@ -185,6 +186,16 @@ static struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = { { .min = 512, .max = 512, .mul = 1024 }, }; +static struct imx_akcodec_fs_mul cs42888_fs_mul[] = { + { .rmin = 8000, .rmax = 48000, .wmin = 256, .wmax = 1024, }, + { .rmin = 64000, .rmax = 96000, .wmin = 128, .wmax = 512, }, + { .rmin = 176400, .rmax = 192000, .wmin = 64, .wmax = 256, }, +}; + +static struct imx_akcodec_tdm_fs_mul cs42888_tdm_fs_mul[] = { + { .min = 256, .max = 256, .mul = 256 }, +}; + static const u32 akcodec_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000, @@ -210,6 +221,14 @@ static const u32 ak5558_tdm_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8, }; +static const u32 cs42888_channels[] = { + 1, 2, 4, 6, 8, +}; + +static const u32 cs42888_tdm_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, +}; + static bool format_is_dsd(struct snd_pcm_hw_params *params) { snd_pcm_format_t format = params_format(params); @@ -241,6 +260,7 @@ static bool codec_is_akcodec(unsigned int type) case CODEC_AK4497: case CODEC_AK5558: case CODEC_AK5552: + case CODEC_CS42888: return true; default: break; @@ -340,13 +360,15 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_tdm_slot(codec_dai, - BIT(slots) - 1, - BIT(slots) - 1, - slots, slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); - return ret; + if (format_is_tdm(link_data)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + BIT(slots) - 1, + BIT(slots) - 1, + slots, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); + return ret; + } } } @@ -609,6 +631,8 @@ static int imx_card_parse_of(struct imx_card_data *data) plat_data->type = CODEC_AK5558; else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) plat_data->type = CODEC_AK5552; + else if (!strcmp(link->codecs->dai_name, "cs42888")) + plat_data->type = CODEC_CS42888; } else { link->codecs = &snd_soc_dummy_dlc; @@ -766,6 +790,12 @@ static int imx_card_probe(struct platform_device *pdev) data->dapm_routes[i].sink = "ASRC-Capture"; data->dapm_routes[i].source = "CPU-Capture"; break; + case CODEC_CS42888: + data->dapm_routes[0].sink = "Playback"; + data->dapm_routes[0].source = "CPU-Playback"; + data->dapm_routes[1].sink = "CPU-Capture"; + data->dapm_routes[1].source = "Capture"; + break; default: break; } @@ -805,6 +835,16 @@ static int imx_card_probe(struct platform_device *pdev) plat_data->support_tdm_channels = ak5558_tdm_channels; plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); break; + case CODEC_CS42888: + plat_data->fs_mul = cs42888_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul); + plat_data->tdm_fs_mul = cs42888_tdm_fs_mul; + plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul); + pla
[PATCH 0/2] ASoC: imx-card: add cs42888 codec support
add cs42888 codec support Chancel Liu (2): ASoC: imx-card: Set mclk for codec ASoC: imx-card: Add CS42888 support sound/soc/fsl/imx-card.c | 59 +++- 1 file changed, 52 insertions(+), 7 deletions(-) -- 2.34.1
[PATCH 1/2] ASoC: fsl_xcvr: enable interrupt of cmdc status update
This enables the interrupt to be asserted when there is a change in Capabilities data structure / Latency request of the CMDC Status register. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_xcvr.c | 4 sound/soc/fsl/fsl_xcvr.h | 1 + 2 files changed, 5 insertions(+) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index beede7344efd..9e24d6462c01 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1265,6 +1265,10 @@ static irqreturn_t irq0_isr(int irq, void *devid) dev_dbg(dev, "DMA write request\n"); isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ; } + if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) { + dev_dbg(dev, "CMDC status update\n"); + isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD; + } if (isr_clr) { regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr); diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 882428592e1a..ce27b13698e7 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -165,6 +165,7 @@ FSL_XCVR_IRQ_MUTE | \ FSL_XCVR_IRQ_FIFO_UOFL_ERR | \ FSL_XCVR_IRQ_HOST_WAKEUP | \ +FSL_XCVR_IRQ_CMDC_STATUS_UPD |\ FSL_XCVR_IRQ_ARC_MODE) #define FSL_XCVR_ISR_CMDC_TX_ENBIT(3) -- 2.34.1
[PATCH 2/2] ASoC: fsl_xcvr: reset RX dpath after wrong preamble
Below preamble error means wrong preamble of IEC958 received, the channel order may be wrong at the moment. FSL_XCVR_IRQ_PREAMBLE_MISMATCH FSL_XCVR_IRQ_UNEXP_PRE_REC FSL_XCVR_IRQ_M_W_PRE_MISMATCH FSL_XCVR_IRQ_B_PRE_MISMATCH All above errors may cause channel swap, to avoid such issues, need to reset the DMAC path. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_xcvr.c | 90 ++-- sound/soc/fsl/fsl_xcvr.h | 4 ++ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 9e24d6462c01..1e0bfd59d511 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -53,6 +53,8 @@ struct fsl_xcvr { struct snd_aes_iec958 rx_iec958; struct snd_aes_iec958 tx_iec958; u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; + struct work_struct work_rst; + spinlock_t lock; /* Protect hw_reset and trigger */ }; static const struct fsl_xcvr_pll_conf { @@ -663,7 +665,10 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - int ret; + unsigned long lock_flags; + int ret = 0; + + spin_lock_irqsave(&xcvr->lock, lock_flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -675,7 +680,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -687,7 +692,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "err updating isr %d\n", ret); - return ret; + goto release_lock; } fallthrough; case FSL_XCVR_MODE_SPDIF: @@ -696,7 +701,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); - return ret; + goto release_lock; } break; } @@ -707,14 +712,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) { dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) { dev_err(dai->dev, "Error while setting IER0: %d\n", ret); - return ret; + goto release_lock; } /* clear DPATH RESET */ @@ -723,7 +728,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } break; @@ -736,14 +741,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -754,7 +759,7 @@ static
[PATCH 0/2] ASoC: fsl_xcvr: enable some interrupts
Enable interrupt of cmdc status update and the interrupts for wrong preamble received. Shengjiu Wang (2): ASoC: fsl_xcvr: enable interrupt of cmdc status update ASoC: fsl_xcvr: reset RX dpath after wrong preamble sound/soc/fsl/fsl_xcvr.c | 94 ++-- sound/soc/fsl/fsl_xcvr.h | 5 +++ 2 files changed, 86 insertions(+), 13 deletions(-) -- 2.34.1
[PATCH] ASoC: fsl_sai: Enable 'FIFO continue on error' FCONT bit
FCONT=1 means On FIFO error, the SAI will continue from the same word that caused the FIFO error to set after the FIFO warning flag has been cleared. Set FCONT bit in control register to avoid the channel swap issue after SAI xrun. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_sai.c | 5 - sound/soc/fsl/fsl_sai.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ab58a4461073..634168d2bb6e 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -613,6 +613,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, val_cr4 |= FSL_SAI_CR4_FRSZ(slots); + /* Set to avoid channel swap */ + val_cr4 |= FSL_SAI_CR4_FCONT; + /* Set to output mode to avoid tri-stated data pins */ if (tx) val_cr4 |= FSL_SAI_CR4_CHMOD; @@ -699,7 +702,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | - FSL_SAI_CR4_CHMOD_MASK, + FSL_SAI_CR4_CHMOD_MASK | FSL_SAI_CR4_FCONT_MASK, val_cr4); regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs), FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index dadbd16ee394..9c4d19fe22c6 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -137,6 +137,7 @@ /* SAI Transmit and Receive Configuration 4 Register */ +#define FSL_SAI_CR4_FCONT_MASK BIT(28) #define FSL_SAI_CR4_FCONT BIT(28) #define FSL_SAI_CR4_FCOMB_SHIFT BIT(26) #define FSL_SAI_CR4_FCOMB_SOFT BIT(27) -- 2.34.1
[PATCH 3/3] ASoC: fsl_micfil: Enable micfil error interrupt
Enable micfil error interrupt, in the error handler, FIFO state and OUT state need to be cleared. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 6ecf46e9ac4c..0930d8c9b8d7 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -651,7 +651,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Enable the module */ ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -667,7 +667,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Disable the module */ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -940,6 +940,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_STAT: case REG_MICFIL_DATACH0: case REG_MICFIL_DATACH1: case REG_MICFIL_DATACH2: @@ -948,6 +949,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_OUT_STAT: case REG_MICFIL_VERID: case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: @@ -1024,6 +1026,8 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) { struct fsl_micfil *micfil = (struct fsl_micfil *)devid; struct platform_device *pdev = micfil->pdev; + u32 fifo_stat_reg; + u32 out_stat_reg; u32 stat_reg; regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); @@ -1040,6 +1044,14 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_FIFO_STAT, + fifo_stat_reg, fifo_stat_reg); + + regmap_read(micfil->regmap, REG_MICFIL_OUT_STAT, &out_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_OUT_STAT, + out_stat_reg, out_stat_reg); + return IRQ_HANDLED; } -- 2.34.1
[PATCH 1/3] ASoC: fsl_micfil: fix regmap_write_bits usage
The last parameter 1 means BIT(0), which should be the correct BIT(X). Fixes: 47a70e6fc9a8 ("ASoC: Add MICFIL SoC Digital Audio Interface driver.") Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 193be098fa5e..c347cb3a4712 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -988,7 +988,7 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, MICFIL_STAT_CHXF(i), - 1); + MICFIL_STAT_CHXF(i)); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { @@ -1023,7 +1023,7 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF, 1); + MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } return IRQ_HANDLED; -- 2.34.1
[PATCH 2/3] ASoC: fsl_micfil: Add mclk enable flag
Previously the mclk is enabled in probe() stage, which is not necessary. Move mclk enablement to hw_params() and mclk disablement to hw_free() will be more efficient. 'mclk_flag' is used for this case. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 29 +++-- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index c347cb3a4712..6ecf46e9ac4c 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -58,6 +58,7 @@ struct fsl_micfil { int vad_detected; struct fsl_micfil_verid verid; struct fsl_micfil_param param; + bool mclk_flag; /* mclk enable flag */ }; struct fsl_micfil_soc_data { @@ -693,7 +694,6 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s clk = micfil->mclk; /* Disable clock first, for it was enabled by pm_runtime */ - clk_disable_unprepare(clk); fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, micfil->pll11k_clk, ratio); ret = clk_prepare_enable(clk); @@ -730,6 +730,8 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + micfil->mclk_flag = true; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); if (ret) return ret; @@ -764,6 +766,17 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_micfil_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(micfil->mclk); + micfil->mclk_flag = false; + + return 0; +} + static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -806,6 +819,7 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { .startup= fsl_micfil_startup, .trigger= fsl_micfil_trigger, .hw_params = fsl_micfil_hw_params, + .hw_free= fsl_micfil_hw_free, }; static struct snd_soc_dai_driver fsl_micfil_dai = { @@ -1279,7 +1293,8 @@ static int fsl_micfil_runtime_suspend(struct device *dev) regcache_cache_only(micfil->regmap, true); - clk_disable_unprepare(micfil->mclk); + if (micfil->mclk_flag) + clk_disable_unprepare(micfil->mclk); clk_disable_unprepare(micfil->busclk); return 0; @@ -1294,10 +1309,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) if (ret < 0) return ret; - ret = clk_prepare_enable(micfil->mclk); - if (ret < 0) { - clk_disable_unprepare(micfil->busclk); - return ret; + if (micfil->mclk_flag) { + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) { + clk_disable_unprepare(micfil->busclk); + return ret; + } } regcache_cache_only(micfil->regmap, false); -- 2.34.1
[PATCH 0/3] ASoC: fsl_micfil: fix and improvement
Fix the usage of regmap_write_bits(). Move mclk clock enablement to late stage. Enable the micfil error interrupt. Shengjiu Wang (3): ASoC: fsl_micfil: fix regmap_write_bits usage ASoC: fsl_micfil: Add mclk enable flag ASoC: fsl_micfil: Enable micfil error interrupt sound/soc/fsl/fsl_micfil.c | 49 ++ 1 file changed, 39 insertions(+), 10 deletions(-) -- 2.34.1
[PATCH v4 7/7] ASoC: fsl_easrc: register m2m platform device
Register m2m platform device,that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_easrc.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index a1a7a90ff5ef..25d1c103df32 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2204,6 +2204,12 @@ static int fsl_easrc_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = fsl_asrc_m2m_init(easrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_disable: @@ -2213,6 +2219,10 @@ static int fsl_easrc_probe(struct platform_device *pdev) static void fsl_easrc_remove(struct platform_device *pdev) { + struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(easrc); + pm_runtime_disable(&pdev->dev); } @@ -2313,10 +2323,29 @@ static int fsl_easrc_runtime_resume(struct device *dev) return ret; } +static int fsl_easrc_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(easrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_easrc_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(easrc); + return ret; +} + static const struct dev_pm_ops fsl_easrc_pm_ops = { RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume) }; static struct platform_driver fsl_easrc_driver = { -- 2.34.1
[PATCH v4 6/7] ASoC: fsl_asrc: register m2m platform device
Register m2m platform device, that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_asrc.c | 37 + 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b1b35954f7ac..b1d13774e2a7 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1384,6 +1384,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_get_sync; } + ret = fsl_asrc_m2m_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_get_sync: @@ -1396,6 +1402,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) static void fsl_asrc_remove(struct platform_device *pdev) { + struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(asrc); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) fsl_asrc_runtime_suspend(&pdev->dev); @@ -1497,10 +1507,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(asrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(asrc); + return ret; +} + static const struct dev_pm_ops fsl_asrc_pm = { - SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { @@ -1538,7 +1567,7 @@ static struct platform_driver fsl_asrc_driver = { .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, - .pm = &fsl_asrc_pm, + .pm = pm_ptr(&fsl_asrc_pm), }, }; module_platform_driver(fsl_asrc_driver); -- 2.34.1
[PATCH v4 5/7] ASoC: fsl_asrc_m2m: Add memory to memory function
Implement the ASRC memory to memory function using the compress framework, user can use this function with compress ioctl interface. This feature can be shared by ASRC and EASRC drivers Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc_common.h | 9 + sound/soc/fsl/fsl_asrc_m2m.c| 727 4 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..bff9c6bda344 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -8,6 +8,7 @@ config SND_SOC_FSL_ASRC depends on HAS_DMA select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_COMPRESS_ACCEL help Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) support for the Freescale CPUs. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ad97244b5cc3..d656a9ab54e3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o -snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 3bdd6ea07c09..0cd595b0f629 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -60,6 +60,7 @@ struct fsl_asrc_m2m_cap { * @buf_len: buffer length of m2m * @dma_buffer: buffer pointers * @first_convert: start of conversion + * @ratio_mod_flag: flag for new ratio modifier * @ratio_mod: ratio modification */ struct fsl_asrc_pair { @@ -84,6 +85,7 @@ struct fsl_asrc_pair { unsigned int buf_len[2]; struct snd_dma_buffer dma_buffer[2]; unsigned int first_convert; + bool ratio_mod_flag; unsigned int ratio_mod; }; @@ -98,6 +100,7 @@ struct fsl_asrc_pair { * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral * @spba_clk: SPBA clock (optional, depending on SoC design) + * @card: compress sound card * @lock: spin lock for resource protection * @pair: pair pointers * @channel_avail: non-occupied channel numbers @@ -131,6 +134,7 @@ struct fsl_asrc { struct clk *mem_clk; struct clk *ipg_clk; struct clk *spba_clk; + struct snd_card *card; spinlock_t lock; /* spin lock for resource protection */ struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; @@ -166,4 +170,9 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; +int fsl_asrc_m2m_init(struct fsl_asrc *asrc); +void fsl_asrc_m2m_exit(struct fsl_asrc *asrc); +int fsl_asrc_m2m_resume(struct fsl_asrc *asrc); +int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc); + #endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c new file mode 100644 index ..693ec0a477a4 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +// Copyright (C) 2019-2024 NXP +// +// Freescale ASRC Memory to Memory (M2M) driver + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_asrc_common.h" + +#define DIR_STR(dir) (dir) == IN ? "in" : "out" + +#define ASRC_xPUT_DMA_CALLBACK(dir) \ + (((dir) == IN) ? asrc_input_dma_callback \ + : asrc_output_dma_callback) + +/* Maximum output and capture buffer size */ +#define ASRC_M2M_BUFFER_SIZE (512 * 1024) + +/* Maximum output and capture period size */ +#define ASRC_M2M_PERIOD_SIZE (48 * 1024) + +/* dma complete callback */ +static void asrc_input_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[IN]); +} + +/* dma complete callback */ +static void asrc_output_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[OUT]); +} + +/** + *asrc_read_last_fifo: read all the remaining data from FIFO + *@pair: Structure pointer of fsl_asrc_pair + *@dma_vaddr: virtual address of capture buffer + *@length: payload length of capture buffer + */ +static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, void *dma_vaddr, u32 *length) +{ + struct fsl_asrc *asrc = pair->asrc; + enum asrc_pair_index index = pair->index; + u32 i, reg, size, t_size = 0, width; + u32 *reg32
[PATCH v4 4/7] ASoC: fsl_easrc: define functions for memory to memory usage
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 --- sound/soc/fsl/fsl_easrc.c | 228 ++ sound/soc/fsl/fsl_easrc.h | 4 + 2 files changed, 232 insertions(+) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 962f30912091..a1a7a90ff5ef 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -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_
[PATCH v4 3/7] ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step 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 --- sound/soc/fsl/fsl_asrc.c| 142 sound/soc/fsl/fsl_asrc.h| 2 + sound/soc/fsl/fsl_asrc_common.h | 61 ++ 3 files changed, 205 insertions(+) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b793263291dc..b1b35954f7ac 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1063,6 +1063,139 @@ 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_prepare(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; + } + + pair->first_convert = 1; + + return 0; +} + +static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair) +{ + if (pair->first_convert) { + fsl_asrc_start_pair(pair); + pair->first_convert = 0; + } + /* +* 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(struct fsl_asrc_pair *pair) +{ + if (!pair->first_convert) { + fsl_asrc_stop_pair(pair); + pair->first_convert = 1; + } + + 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_get_cap(struct fsl_asrc_m2m_cap *cap) +{ + cap->fmt_in = FSL_ASRC_FORMATS; + cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8; + + cap->rate_in = supported_asrc_rate; + cap->rate_in_count = ARRAY_S
[PATCH v4 2/7] ALSA: compress: Add output rate and output format support
Add 'pcm_format' for struct snd_codec, add 'pcm_formats' for struct snd_codec_desc, these are used for accelerator usage. Current accelerator example is sample rate converter (SRC). Define struct snd_codec_desc_src for descript minmum and maxmum sample rates. And add 'src_d' in union snd_codec_options structure. These are mainly used for capbility query. Signed-off-by: Jaroslav Kysela Signed-off-by: Shengjiu Wang --- include/uapi/sound/compress_params.h | 23 +-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ddc77322d571..bc7648a30746 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -334,6 +334,14 @@ union snd_codec_options { struct snd_dec_wma wma_d; struct snd_dec_alac alac_d; struct snd_dec_ape ape_d; + struct { + __u32 out_sample_rate; + } src_d; +} __attribute__((packed, aligned(4))); + +struct snd_codec_desc_src { + __u32 out_sample_rate_min; + __u32 out_sample_rate_max; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities @@ -347,6 +355,9 @@ union snd_codec_options { * @modes: Supported modes. See SND_AUDIOMODE defines * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines * @min_buffer: Minimum buffer size handled by codec implementation + * @pcm_formats: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) + * @u_space: union space (for codec dependent data) * @reserved: reserved for future use * * This structure provides a scalar value for profiles, modes and stream @@ -370,7 +381,12 @@ struct snd_codec_desc { __u32 modes; __u32 formats; __u32 min_buffer; - __u32 reserved[15]; + __u32 pcm_formats; + union { + __u32 u_space[6]; + struct snd_codec_desc_src src; + } __attribute__((packed, aligned(4))); + __u32 reserved[8]; } __attribute__((packed, aligned(4))); /** struct snd_codec @@ -395,6 +411,8 @@ struct snd_codec_desc { * @align: Block alignment in bytes of an audio sample. * Only required for PCM or IEC formats. * @options: encoder-specific settings + * @pcm_format: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) * @reserved: reserved for future use */ @@ -411,7 +429,8 @@ struct snd_codec { __u32 format; __u32 align; union snd_codec_options options; - __u32 reserved[3]; + __u32 pcm_format; + __u32 reserved[2]; } __attribute__((packed, aligned(4))); #endif -- 2.34.1
[PATCH v4 0/7] ASoC: fsl: add memory to memory function for ASRC
This function is base on the accelerator implementation for compress API: https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ Add it to this patch set. Audio signal processing also has the requirement for memory to memory similar as Video. This asrc memory to memory (memory ->asrc->memory) case is a non real time use case. User fills the input buffer to the asrc module, after conversion, then asrc sends back the output buffer to user. So it is not a traditional ALSA playback and capture case. Because we had implemented the "memory -> asrc ->i2s device-> codec" use case in ALSA. Now the "memory->asrc->memory" needs to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining the code to make it can be shared by the "memory->asrc->memory" driver. Other change is to add memory to memory support for two kinds of i.MX ASRC modules. changes in v4: - remove the RFC tag, no comments receive in v3 - Add Jaroslav Kysela's patch in this patch set. because it may be better for reviewing in a full patch set. - Fix the list_for_each_entry_reverse to list_for_each_entry_safe_reverse - Fix some coding style issues in Jaroslav Kysela's patch changes in v3: - use Jaroslav's suggestion for header file compress_params.h (PATCH 01) - remove the ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE definition - remove ASRC_RATIO_MOD in this version because it uses .set_metadata() Will wait Jaroslav's update or other better method in the future. - Address some comments from Pierre. changes in v2: - Remove the changes in compress API - drop the SNDRV_COMPRESS_SRC_RATIO_MOD - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src - define private metadata key value ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD Jaroslav Kysela (1): ALSA: compress_offload: introduce accel operation mode Shengjiu Wang (6): ALSA: compress: Add output rate and output format support ASoC: fsl_asrc: define functions for memory to memory usage ASoC: fsl_easrc: define functions for memory to memory usage ASoC: fsl_asrc_m2m: Add memory to memory function ASoC: fsl_asrc: register m2m platform device ASoC: fsl_easrc: register m2m platform device .../sound/designs/compress-accel.rst | 136 include/sound/compress_driver.h | 46 ++ include/uapi/sound/compress_offload.h | 63 +- include/uapi/sound/compress_params.h | 23 +- sound/core/Kconfig| 3 + sound/core/compress_offload.c | 351 - sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile| 2 +- sound/soc/fsl/fsl_asrc.c | 179 - sound/soc/fsl/fsl_asrc.h | 2 + sound/soc/fsl/fsl_asrc_common.h | 70 ++ sound/soc/fsl/fsl_asrc_m2m.c | 727 ++ sound/soc/fsl/fsl_easrc.c | 261 ++- sound/soc/fsl/fsl_easrc.h | 4 + 14 files changed, 1851 insertions(+), 17 deletions(-) create mode 100644 Documentation/sound/designs/compress-accel.rst create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c -- 2.34.1
[PATCH v4 1/7] ALSA: compress_offload: introduce accel operation mode
From: Jaroslav Kysela There is a requirement to expose the audio hardware that accelerates various tasks for user space such as sample rate converters, compressed stream decoders, etc. This is description for the API extension for the compress ALSA API which is able to handle "tasks" that are not bound to real-time operations and allows for the serialization of operations. For details, refer to "compress-accel.rst" document. Cc: Mark Brown Cc: Shengjiu Wang Cc: Nicolas Dufresne Cc: Amadeusz Sławiński Cc: Pierre-Louis Bossart Cc: Vinod Koul Signed-off-by: Jaroslav Kysela Signed-off-by: Shengjiu Wang --- .../sound/designs/compress-accel.rst | 136 +++ include/sound/compress_driver.h | 46 +++ include/uapi/sound/compress_offload.h | 63 +++- sound/core/Kconfig| 3 + sound/core/compress_offload.c | 351 +- 5 files changed, 591 insertions(+), 8 deletions(-) create mode 100644 Documentation/sound/designs/compress-accel.rst diff --git a/Documentation/sound/designs/compress-accel.rst b/Documentation/sound/designs/compress-accel.rst new file mode 100644 index ..cfe4fa645ab2 --- /dev/null +++ b/Documentation/sound/designs/compress-accel.rst @@ -0,0 +1,136 @@ +.. SPDX-License-Identifier: GPL-2.0 + +== +ALSA Co-processor Acceleration API +== + +Jaroslav Kysela + + +Overview + + +There is a requirement to expose the audio hardware that accelerates various +tasks for user space such as sample rate converters, compressed +stream decoders, etc. + +This is description for the API extension for the compress ALSA API which +is able to handle "tasks" that are not bound to real-time operations +and allows for the serialization of operations. + +Requirements + + +The main requirements are: + +- serialization of multiple tasks for user space to allow multiple + operations without user space intervention + +- separate buffers (input + output) for each operation + +- expose buffers using mmap to user space + +- signal user space when the task is finished (standard poll mechanism) + +Design +== + +A new direction SND_COMPRESS_ACCEL is introduced to identify +the passthrough API. + +The API extension shares device enumeration and parameters handling from +the main compressed API. All other realtime streaming ioctls are deactivated +and a new set of task related ioctls are introduced. The standard +read/write/mmap I/O operations are not supported in the passthrough device. + +Device ("stream") state handling is reduced to OPEN/SETUP. All other +states are not available for the passthrough mode. + +Data I/O mechanism is using standard dma-buf interface with all advantages +like mmap, standard I/O, buffer sharing etc. One buffer is used for the +input data and second (separate) buffer is used for the output data. Each task +have separate I/O buffers. + +For the buffering parameters, the fragments means a limit of allocated tasks +for given device. The fragment_size limits the input buffer size for the given +device. The output buffer size is determined by the driver (may be different +from the input buffer size). + +State Machine += + +The passthrough audio stream state machine is described below : + + +--+ + | | + | OPEN | + | | + +--+ + | + | + | compr_set_params() + | + v + all passthrough task ops +--+ + +| | + || SETUP | + || + |+--+ + | | + +--+ + + +Passthrough operations (ioctls) +=== + +All operations are protected using stream->device->lock (mutex). + +CREATE +-- +Creates a set of input/output buffers. The input buffer size is +fragment_size. Allocates unique seqno. + +The hardware drivers allocate internal 'struct dma_buf' for both input and +output buffers (using 'dma_buf_export()' function). The anonymous +file descriptors for those buffers are passed to user space. + +FREE + +Free a set of input/output buffers. If a task is active, the stop +operation is executed before. If seqno is zero, operation is executed for all +tasks. + +START +- +Starts (queues) a task. There are two cases
Re: [RFC PATCH v3 0/6] ASoC: fsl: add memory to memory function for ASRC
Hi Jaroslav On Fri, Sep 13, 2024 at 10:29 AM Shengjiu Wang wrote: > > On Fri, Sep 6, 2024 at 6:05 PM Shengjiu Wang wrote: > > > > This function is base on the accelerator implementation > > for compress API: > > https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ > > Hi Jaroslav > > Shall I add this patch to my patch set next time? Last time I > reported an issue > about "list_for_each_entry_safe_reverse", I can help to add it. or > will you send > another version by yourself? A gentle reminder, look forward to your reply. Thanks. Best regards Shengjiu Wang > > Best regards > Shengjiu Wang > > > > > Audio signal processing also has the requirement for memory to > > memory similar as Video. > > > > This asrc memory to memory (memory ->asrc->memory) case is a non > > real time use case. > > > > User fills the input buffer to the asrc module, after conversion, then asrc > > sends back the output buffer to user. So it is not a traditional ALSA > > playback > > and capture case. > > > > Because we had implemented the "memory -> asrc ->i2s device-> codec" > > use case in ALSA. Now the "memory->asrc->memory" needs > > to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining > > the code to make it can be shared by the "memory->asrc->memory" > > driver. > > > > Other change is to add memory to memory support for two kinds of i.MX ASRC > > modules. > > > > changes in v3: > > - use Jaroslav's suggestion for header file compress_params.h (PATCH 01) > > - remove the ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE definition > > - remove ASRC_RATIO_MOD in this version because it uses .set_metadata() > > Will wait Jaroslav's update or other better method in the future. > > - Address some comments from Pierre. > > > > changes in v2: > > - Remove the changes in compress API > > - drop the SNDRV_COMPRESS_SRC_RATIO_MOD > > - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src > > - define private metadata key value > > ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD > > > > Shengjiu Wang (6): > > ALSA: compress: Add output rate and output format support > > ASoC: fsl_asrc: define functions for memory to memory usage > > ASoC: fsl_easrc: define functions for memory to memory usage > > ASoC: fsl_asrc_m2m: Add memory to memory function > > ASoC: fsl_asrc: register m2m platform device > > ASoC: fsl_easrc: register m2m platform device > > > > include/uapi/sound/compress_params.h | 23 +- > > sound/soc/fsl/Kconfig| 1 + > > sound/soc/fsl/Makefile | 2 +- > > sound/soc/fsl/fsl_asrc.c | 179 ++- > > sound/soc/fsl/fsl_asrc.h | 2 + > > sound/soc/fsl/fsl_asrc_common.h | 70 +++ > > sound/soc/fsl/fsl_asrc_m2m.c | 727 +++ > > sound/soc/fsl/fsl_easrc.c| 261 +- > > sound/soc/fsl/fsl_easrc.h| 4 + > > 9 files changed, 1260 insertions(+), 9 deletions(-) > > create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c > > > > -- > > 2.34.1 > >
Re: [RFC PATCH v3 0/6] ASoC: fsl: add memory to memory function for ASRC
On Fri, Sep 6, 2024 at 6:05 PM Shengjiu Wang wrote: > > This function is base on the accelerator implementation > for compress API: > https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ Hi Jaroslav Shall I add this patch to my patch set next time? Last time I reported an issue about "list_for_each_entry_safe_reverse", I can help to add it. or will you send another version by yourself? Best regards Shengjiu Wang > > Audio signal processing also has the requirement for memory to > memory similar as Video. > > This asrc memory to memory (memory ->asrc->memory) case is a non > real time use case. > > User fills the input buffer to the asrc module, after conversion, then asrc > sends back the output buffer to user. So it is not a traditional ALSA playback > and capture case. > > Because we had implemented the "memory -> asrc ->i2s device-> codec" > use case in ALSA. Now the "memory->asrc->memory" needs > to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining > the code to make it can be shared by the "memory->asrc->memory" > driver. > > Other change is to add memory to memory support for two kinds of i.MX ASRC > modules. > > changes in v3: > - use Jaroslav's suggestion for header file compress_params.h (PATCH 01) > - remove the ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE definition > - remove ASRC_RATIO_MOD in this version because it uses .set_metadata() > Will wait Jaroslav's update or other better method in the future. > - Address some comments from Pierre. > > changes in v2: > - Remove the changes in compress API > - drop the SNDRV_COMPRESS_SRC_RATIO_MOD > - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src > - define private metadata key value > ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD > > Shengjiu Wang (6): > ALSA: compress: Add output rate and output format support > ASoC: fsl_asrc: define functions for memory to memory usage > ASoC: fsl_easrc: define functions for memory to memory usage > ASoC: fsl_asrc_m2m: Add memory to memory function > ASoC: fsl_asrc: register m2m platform device > ASoC: fsl_easrc: register m2m platform device > > include/uapi/sound/compress_params.h | 23 +- > sound/soc/fsl/Kconfig| 1 + > sound/soc/fsl/Makefile | 2 +- > sound/soc/fsl/fsl_asrc.c | 179 ++- > sound/soc/fsl/fsl_asrc.h | 2 + > sound/soc/fsl/fsl_asrc_common.h | 70 +++ > sound/soc/fsl/fsl_asrc_m2m.c | 727 +++ > sound/soc/fsl/fsl_easrc.c| 261 +- > sound/soc/fsl/fsl_easrc.h| 4 + > 9 files changed, 1260 insertions(+), 9 deletions(-) > create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c > > -- > 2.34.1 >
[RFC PATCH v3 6/6] ASoC: fsl_easrc: register m2m platform device
Register m2m platform device,that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_easrc.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index a1a7a90ff5ef..25d1c103df32 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2204,6 +2204,12 @@ static int fsl_easrc_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = fsl_asrc_m2m_init(easrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_disable: @@ -2213,6 +2219,10 @@ static int fsl_easrc_probe(struct platform_device *pdev) static void fsl_easrc_remove(struct platform_device *pdev) { + struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(easrc); + pm_runtime_disable(&pdev->dev); } @@ -2313,10 +2323,29 @@ static int fsl_easrc_runtime_resume(struct device *dev) return ret; } +static int fsl_easrc_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(easrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_easrc_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(easrc); + return ret; +} + static const struct dev_pm_ops fsl_easrc_pm_ops = { RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume) }; static struct platform_driver fsl_easrc_driver = { -- 2.34.1
[RFC PATCH v3 5/6] ASoC: fsl_asrc: register m2m platform device
Register m2m platform device, that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_asrc.c | 37 + 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b1b35954f7ac..b1d13774e2a7 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1384,6 +1384,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_get_sync; } + ret = fsl_asrc_m2m_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_get_sync: @@ -1396,6 +1402,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) static void fsl_asrc_remove(struct platform_device *pdev) { + struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(asrc); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) fsl_asrc_runtime_suspend(&pdev->dev); @@ -1497,10 +1507,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(asrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(asrc); + return ret; +} + static const struct dev_pm_ops fsl_asrc_pm = { - SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { @@ -1538,7 +1567,7 @@ static struct platform_driver fsl_asrc_driver = { .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, - .pm = &fsl_asrc_pm, + .pm = pm_ptr(&fsl_asrc_pm), }, }; module_platform_driver(fsl_asrc_driver); -- 2.34.1
[RFC PATCH v3 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
Implement the ASRC memory to memory function using the compress framework, user can use this function with compress ioctl interface. This feature can be shared by ASRC and EASRC drivers Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc_common.h | 9 + sound/soc/fsl/fsl_asrc_m2m.c| 727 4 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..bff9c6bda344 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -8,6 +8,7 @@ config SND_SOC_FSL_ASRC depends on HAS_DMA select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_COMPRESS_ACCEL help Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) support for the Freescale CPUs. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ad97244b5cc3..d656a9ab54e3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o -snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 3bdd6ea07c09..0cd595b0f629 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -60,6 +60,7 @@ struct fsl_asrc_m2m_cap { * @buf_len: buffer length of m2m * @dma_buffer: buffer pointers * @first_convert: start of conversion + * @ratio_mod_flag: flag for new ratio modifier * @ratio_mod: ratio modification */ struct fsl_asrc_pair { @@ -84,6 +85,7 @@ struct fsl_asrc_pair { unsigned int buf_len[2]; struct snd_dma_buffer dma_buffer[2]; unsigned int first_convert; + bool ratio_mod_flag; unsigned int ratio_mod; }; @@ -98,6 +100,7 @@ struct fsl_asrc_pair { * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral * @spba_clk: SPBA clock (optional, depending on SoC design) + * @card: compress sound card * @lock: spin lock for resource protection * @pair: pair pointers * @channel_avail: non-occupied channel numbers @@ -131,6 +134,7 @@ struct fsl_asrc { struct clk *mem_clk; struct clk *ipg_clk; struct clk *spba_clk; + struct snd_card *card; spinlock_t lock; /* spin lock for resource protection */ struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; @@ -166,4 +170,9 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; +int fsl_asrc_m2m_init(struct fsl_asrc *asrc); +void fsl_asrc_m2m_exit(struct fsl_asrc *asrc); +int fsl_asrc_m2m_resume(struct fsl_asrc *asrc); +int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc); + #endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c new file mode 100644 index ..693ec0a477a4 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +// Copyright (C) 2019-2024 NXP +// +// Freescale ASRC Memory to Memory (M2M) driver + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_asrc_common.h" + +#define DIR_STR(dir) (dir) == IN ? "in" : "out" + +#define ASRC_xPUT_DMA_CALLBACK(dir) \ + (((dir) == IN) ? asrc_input_dma_callback \ + : asrc_output_dma_callback) + +/* Maximum output and capture buffer size */ +#define ASRC_M2M_BUFFER_SIZE (512 * 1024) + +/* Maximum output and capture period size */ +#define ASRC_M2M_PERIOD_SIZE (48 * 1024) + +/* dma complete callback */ +static void asrc_input_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[IN]); +} + +/* dma complete callback */ +static void asrc_output_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[OUT]); +} + +/** + *asrc_read_last_fifo: read all the remaining data from FIFO + *@pair: Structure pointer of fsl_asrc_pair + *@dma_vaddr: virtual address of capture buffer + *@length: payload length of capture buffer + */ +static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, void *dma_vaddr, u32 *length) +{ + struct fsl_asrc *asrc = pair->asrc; + enum asrc_pair_index index = pair->index; + u32 i, reg, size, t_size = 0, width; + u32 *reg32
[RFC PATCH v3 3/6] ASoC: fsl_easrc: define functions for memory to memory usage
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 --- sound/soc/fsl/fsl_easrc.c | 228 ++ sound/soc/fsl/fsl_easrc.h | 4 + 2 files changed, 232 insertions(+) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 962f30912091..a1a7a90ff5ef 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -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_
[RFC PATCH v3 2/6] ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step 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 --- sound/soc/fsl/fsl_asrc.c| 142 sound/soc/fsl/fsl_asrc.h| 2 + sound/soc/fsl/fsl_asrc_common.h | 61 ++ 3 files changed, 205 insertions(+) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b793263291dc..b1b35954f7ac 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1063,6 +1063,139 @@ 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_prepare(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; + } + + pair->first_convert = 1; + + return 0; +} + +static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair) +{ + if (pair->first_convert) { + fsl_asrc_start_pair(pair); + pair->first_convert = 0; + } + /* +* 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(struct fsl_asrc_pair *pair) +{ + if (!pair->first_convert) { + fsl_asrc_stop_pair(pair); + pair->first_convert = 1; + } + + 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_get_cap(struct fsl_asrc_m2m_cap *cap) +{ + cap->fmt_in = FSL_ASRC_FORMATS; + cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8; + + cap->rate_in = supported_asrc_rate; + cap->rate_in_count = ARRAY_S
[RFC PATCH v3 1/6] ALSA: compress: Add output rate and output format support
Add 'pcm_format' for struct snd_codec, add 'pcm_formats' for struct snd_codec_desc, these are used for accelerator usage. Current accelerator example is sample rate converter (SRC). Define struct snd_codec_desc_src for descript minmum and maxmum sample rates. And add 'src_d' in union snd_codec_options structure. These are mainly used for capbility query. Signed-off-by: Jaroslav Kysela Signed-off-by: Shengjiu Wang --- include/uapi/sound/compress_params.h | 23 +-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ddc77322d571..bc7648a30746 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -334,6 +334,14 @@ union snd_codec_options { struct snd_dec_wma wma_d; struct snd_dec_alac alac_d; struct snd_dec_ape ape_d; + struct { + __u32 out_sample_rate; + } src_d; +} __attribute__((packed, aligned(4))); + +struct snd_codec_desc_src { + __u32 out_sample_rate_min; + __u32 out_sample_rate_max; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities @@ -347,6 +355,9 @@ union snd_codec_options { * @modes: Supported modes. See SND_AUDIOMODE defines * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines * @min_buffer: Minimum buffer size handled by codec implementation + * @pcm_formats: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) + * @u_space: union space (for codec dependent data) * @reserved: reserved for future use * * This structure provides a scalar value for profiles, modes and stream @@ -370,7 +381,12 @@ struct snd_codec_desc { __u32 modes; __u32 formats; __u32 min_buffer; - __u32 reserved[15]; + __u32 pcm_formats; + union { + __u32 u_space[6]; + struct snd_codec_desc_src src; + } __attribute__((packed, aligned(4))); + __u32 reserved[8]; } __attribute__((packed, aligned(4))); /** struct snd_codec @@ -395,6 +411,8 @@ struct snd_codec_desc { * @align: Block alignment in bytes of an audio sample. * Only required for PCM or IEC formats. * @options: encoder-specific settings + * @pcm_format: Output (for decoders) or input (for encoders) + * PCM formats (required to accel mode, 0 for other modes) * @reserved: reserved for future use */ @@ -411,7 +429,8 @@ struct snd_codec { __u32 format; __u32 align; union snd_codec_options options; - __u32 reserved[3]; + __u32 pcm_format; + __u32 reserved[2]; } __attribute__((packed, aligned(4))); #endif -- 2.34.1
[RFC PATCH v3 0/6] ASoC: fsl: add memory to memory function for ASRC
This function is base on the accelerator implementation for compress API: https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ Audio signal processing also has the requirement for memory to memory similar as Video. This asrc memory to memory (memory ->asrc->memory) case is a non real time use case. User fills the input buffer to the asrc module, after conversion, then asrc sends back the output buffer to user. So it is not a traditional ALSA playback and capture case. Because we had implemented the "memory -> asrc ->i2s device-> codec" use case in ALSA. Now the "memory->asrc->memory" needs to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining the code to make it can be shared by the "memory->asrc->memory" driver. Other change is to add memory to memory support for two kinds of i.MX ASRC modules. changes in v3: - use Jaroslav's suggestion for header file compress_params.h (PATCH 01) - remove the ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE definition - remove ASRC_RATIO_MOD in this version because it uses .set_metadata() Will wait Jaroslav's update or other better method in the future. - Address some comments from Pierre. changes in v2: - Remove the changes in compress API - drop the SNDRV_COMPRESS_SRC_RATIO_MOD - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src - define private metadata key value ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD Shengjiu Wang (6): ALSA: compress: Add output rate and output format support ASoC: fsl_asrc: define functions for memory to memory usage ASoC: fsl_easrc: define functions for memory to memory usage ASoC: fsl_asrc_m2m: Add memory to memory function ASoC: fsl_asrc: register m2m platform device ASoC: fsl_easrc: register m2m platform device include/uapi/sound/compress_params.h | 23 +- sound/soc/fsl/Kconfig| 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc.c | 179 ++- sound/soc/fsl/fsl_asrc.h | 2 + sound/soc/fsl/fsl_asrc_common.h | 70 +++ sound/soc/fsl/fsl_asrc_m2m.c | 727 +++ sound/soc/fsl/fsl_easrc.c| 261 +- sound/soc/fsl/fsl_easrc.h| 4 + 9 files changed, 1260 insertions(+), 9 deletions(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c -- 2.34.1
Re: [RFC PATCH v2 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
On Tue, Aug 20, 2024 at 3:42 PM Jaroslav Kysela wrote: > > On 20. 08. 24 9:37, Shengjiu Wang wrote: > > On Tue, Aug 20, 2024 at 2:59 PM Pierre-Louis Bossart > > wrote: > >> > >> > >> > >> On 8/20/24 04:53, Shengjiu Wang wrote: > >>> On Mon, Aug 19, 2024 at 3:42 PM Pierre-Louis Bossart > >>> wrote: > >>>> > >>>> > >>>> > >>>> On 8/16/24 12:42, Shengjiu Wang wrote: > >>>>> Implement the ASRC memory to memory function using > >>>>> the compress framework, user can use this function with > >>>>> compress ioctl interface. > >>>>> > >>>>> Define below private metadata key value for output > >>>>> format, output rate and ratio modifier configuration. > >>>>> ASRC_OUTPUT_FORMAT 0x8001 > >>>>> ASRC_OUTPUT_RATE 0x8002 > >>>>> ASRC_RATIO_MOD 0x8003 > >>>> > >>>> Can the output format/rate change at run-time? > >>> > >>> Seldom I think. > >>> > >>>> > >>>> If no, then these parameters should be moved somewhere else - e.g. > >>>> hw_params or something. > >>> > >>> This means I will do some changes in compress_params.h, add > >>> output format and output rate definition, follow Jaroslav's example > >>> right? > >> > >> yes, having parameters for the PCM case would make sense. > >> > >>>> I am still not very clear on the expanding the SET_METADATA ioctl to > >>>> deal with the ratio changes. This isn't linked to the control layer as > >>>> suggested before, and there's no precedent of calling it multiple times > >>>> during streaming. > >>> > >>> Which control layer? if you means the snd_kcontrol_new? it is bound > >>> with sound card, but in my case, I need to the control bind with > >>> the snd_compr_stream to support multi streams/instances. > >> > >> I can only quote Jaroslav's previous answer: > >> > >> " > >> This argument is not valid. The controls are bound to the card, but the > >> element identifiers have already iface (interface), device and subdevice > >> numbers. We are using controls for PCM devices for example. The binding > >> is straight. > >> > >> Just add SNDRV_CTL_ELEM_IFACE_COMPRESS define and specify the compress > >> device number in the 'struct snd_ctl_elem_id'. > >> " > > > > I don't think it is doable, or at least I don't know how to do it. > > > > My case is just one card/one device/one subdevice. can't use it to > > distinguish multi streams. > > I already wrote that the compress core code should be extended to support > subdevices like other ALSA APIs. I'll work on it. For now, just add support > for one converter. Thanks. What does this subdevices mean? Is it equal to the compress streams? When I call snd_compr_ops.open(), it means to create an instance, the instance is created at runtime (call open()), not created when the sound card is created. Best regards Shengjiu Wang > > Jaroslav > > -- > Jaroslav Kysela > Linux Sound Maintainer; ALSA Project; Red Hat, Inc. >
Re: [RFC PATCH v2 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
On Tue, Aug 20, 2024 at 2:59 PM Pierre-Louis Bossart wrote: > > > > On 8/20/24 04:53, Shengjiu Wang wrote: > > On Mon, Aug 19, 2024 at 3:42 PM Pierre-Louis Bossart > > wrote: > >> > >> > >> > >> On 8/16/24 12:42, Shengjiu Wang wrote: > >>> Implement the ASRC memory to memory function using > >>> the compress framework, user can use this function with > >>> compress ioctl interface. > >>> > >>> Define below private metadata key value for output > >>> format, output rate and ratio modifier configuration. > >>> ASRC_OUTPUT_FORMAT 0x8001 > >>> ASRC_OUTPUT_RATE 0x8002 > >>> ASRC_RATIO_MOD 0x8003 > >> > >> Can the output format/rate change at run-time? > > > > Seldom I think. > > > >> > >> If no, then these parameters should be moved somewhere else - e.g. > >> hw_params or something. > > > > This means I will do some changes in compress_params.h, add > > output format and output rate definition, follow Jaroslav's example > > right? > > yes, having parameters for the PCM case would make sense. > > >> I am still not very clear on the expanding the SET_METADATA ioctl to > >> deal with the ratio changes. This isn't linked to the control layer as > >> suggested before, and there's no precedent of calling it multiple times > >> during streaming. > > > > Which control layer? if you means the snd_kcontrol_new? it is bound > > with sound card, but in my case, I need to the control bind with > > the snd_compr_stream to support multi streams/instances. > > I can only quote Jaroslav's previous answer: > > " > This argument is not valid. The controls are bound to the card, but the > element identifiers have already iface (interface), device and subdevice > numbers. We are using controls for PCM devices for example. The binding > is straight. > > Just add SNDRV_CTL_ELEM_IFACE_COMPRESS define and specify the compress > device number in the 'struct snd_ctl_elem_id'. > " I don't think it is doable, or at least I don't know how to do it. My case is just one card/one device/one subdevice. can't use it to distinguish multi streams. > > >> I also wonder how it was tested since tinycompress does not support this? > > > > I wrote a unit test to test these ASRC M2M functions. > > This should be shared IMHO, usually when we add/extend a new interface > it's best to have a userspace test program that can be used by others. After Jaroslav updates the tinycompress, I can update this example to it. > > >>> +static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc, > >>> + struct snd_compr_codec_caps *codec) > >>> +{ > >>> + struct fsl_asrc_m2m_cap cap; > >>> + __u32 rates[MAX_NUM_BITRATES]; > >>> + snd_pcm_format_t k; > >>> + int i = 0, j = 0; > >>> + int ret; > >>> + > >>> + ret = asrc->m2m_get_cap(&cap); > >>> + if (ret) > >>> + return -EINVAL; > >>> + > >>> + if (cap.rate_in & SNDRV_PCM_RATE_5512) > >>> + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_5512); > >> > >> this doesn't sound compatible with the patch2 definitions? > >> > >> cap->rate_in = SNDRV_PCM_RATE_8000_768000; > > > > This ASRC M2M driver is designed for two kinds of hw ASRC modules. > > > > one cap is : cap->rate_in = SNDRV_PCM_RATE_8000_192000 | > > SNDRV_PCM_RATE_5512; > > another is : cap->rate_in = SNDRV_PCM_RATE_8000_768000; > > they are in patch2 and patch3 > > > > > >> > >>> + if (cap.rate_in & SNDRV_PCM_RATE_8000) > >>> + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_8000); > >>> + if (cap.rate_in & SNDRV_PCM_RATE_11025) > >>> + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_11025); > >>> + if (cap.rate_in & SNDRV_PCM_RATE_16000) > >>> + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_16000); > >>> + if (cap.rate_in & SNDRV_PCM_RATE_22050) > >>> + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_22050); > >> > >> missing 24 kHz > > > > There is no SNDRV_PCM_RATE_24000 in ALSA. > > Right, but that doesn't mean 24kHz cannot be supported. We
Re: [RFC PATCH v2 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
On Mon, Aug 19, 2024 at 3:42 PM Pierre-Louis Bossart wrote: > > > > On 8/16/24 12:42, Shengjiu Wang wrote: > > Implement the ASRC memory to memory function using > > the compress framework, user can use this function with > > compress ioctl interface. > > > > Define below private metadata key value for output > > format, output rate and ratio modifier configuration. > > ASRC_OUTPUT_FORMAT 0x8001 > > ASRC_OUTPUT_RATE 0x8002 > > ASRC_RATIO_MOD 0x8003 > > Can the output format/rate change at run-time? Seldom I think. > > If no, then these parameters should be moved somewhere else - e.g. > hw_params or something. This means I will do some changes in compress_params.h, add output format and output rate definition, follow Jaroslav's example right? > > I am still not very clear on the expanding the SET_METADATA ioctl to > deal with the ratio changes. This isn't linked to the control layer as > suggested before, and there's no precedent of calling it multiple times > during streaming. Which control layer? if you means the snd_kcontrol_new? it is bound with sound card, but in my case, I need to the control bind with the snd_compr_stream to support multi streams/instances. > > I also wonder how it was tested since tinycompress does not support this? I wrote a unit test to test these ASRC M2M functions. > > > > +static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc, > > + struct snd_compr_codec_caps *codec) > > +{ > > + struct fsl_asrc_m2m_cap cap; > > + __u32 rates[MAX_NUM_BITRATES]; > > + snd_pcm_format_t k; > > + int i = 0, j = 0; > > + int ret; > > + > > + ret = asrc->m2m_get_cap(&cap); > > + if (ret) > > + return -EINVAL; > > + > > + if (cap.rate_in & SNDRV_PCM_RATE_5512) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_5512); > > this doesn't sound compatible with the patch2 definitions? > > cap->rate_in = SNDRV_PCM_RATE_8000_768000; This ASRC M2M driver is designed for two kinds of hw ASRC modules. one cap is : cap->rate_in = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_5512; another is : cap->rate_in = SNDRV_PCM_RATE_8000_768000; they are in patch2 and patch3 > > > + if (cap.rate_in & SNDRV_PCM_RATE_8000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_8000); > > + if (cap.rate_in & SNDRV_PCM_RATE_11025) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_11025); > > + if (cap.rate_in & SNDRV_PCM_RATE_16000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_16000); > > + if (cap.rate_in & SNDRV_PCM_RATE_22050) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_22050); > > missing 24 kHz There is no SNDRV_PCM_RATE_24000 in ALSA. > > > + if (cap.rate_in & SNDRV_PCM_RATE_32000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_32000); > > + if (cap.rate_in & SNDRV_PCM_RATE_44100) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_44100); > > + if (cap.rate_in & SNDRV_PCM_RATE_48000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_48000); > > missing 64kHz Yes, will add it. Best regards Shengjiu Wang > > > + if (cap.rate_in & SNDRV_PCM_RATE_88200) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_88200); > > + if (cap.rate_in & SNDRV_PCM_RATE_96000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_96000); > > + if (cap.rate_in & SNDRV_PCM_RATE_176400) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_176400); > > + if (cap.rate_in & SNDRV_PCM_RATE_192000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_192000); > > + if (cap.rate_in & SNDRV_PCM_RATE_352800) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_352800); > > + if (cap.rate_in & SNDRV_PCM_RATE_384000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_384000); > > + if (cap.rate_in & SNDRV_PCM_RATE_705600) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_705600); > > + if (cap.rate_in & SNDRV_PCM_RATE_768000) > > + rates[i++] = snd_pcm_rate_bit_to_rate(SNDRV_PCM_RATE_768000); > > + > > + pcm_for_each_format(k) { > > + if (pcm_format_to_bits(k) & cap.fmt_in) { > > + codec->descriptor[j].max_ch = cap.chan_max; > > + memcpy(codec->descriptor[j].sample_rates, rates, i * > > sizeof(__u32)); > > + codec->descriptor[j].num_sample_rates = i; > > + codec->descriptor[j].formats = k; > > + j++; > > + } > > + } > > + > > + codec->codec = SND_AUDIOCODEC_PCM; > > + codec->num_descriptors = j; > > + return 0; > >
[RFC PATCH v2 6/6] ASoC: fsl_easrc: register m2m platform device
Register m2m platform device,that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_easrc.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 959a8e2dd716..98adbae082fa 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2202,6 +2202,12 @@ static int fsl_easrc_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = fsl_asrc_m2m_init(easrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_disable: @@ -2211,6 +2217,10 @@ static int fsl_easrc_probe(struct platform_device *pdev) static void fsl_easrc_remove(struct platform_device *pdev) { + struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(easrc); + pm_runtime_disable(&pdev->dev); } @@ -2311,10 +2321,29 @@ static int fsl_easrc_runtime_resume(struct device *dev) return ret; } +static int fsl_easrc_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(easrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_easrc_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(easrc); + return ret; +} + static const struct dev_pm_ops fsl_easrc_pm_ops = { RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume) }; static struct platform_driver fsl_easrc_driver = { -- 2.34.1
[RFC PATCH v2 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
Implement the ASRC memory to memory function using the compress framework, user can use this function with compress ioctl interface. Define below private metadata key value for output format, output rate and ratio modifier configuration. ASRC_OUTPUT_FORMAT 0x8001 ASRC_OUTPUT_RATE 0x8002 ASRC_RATIO_MOD 0x8003 This feature can be shared by ASRC and EASRC drivers Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc_common.h | 9 + sound/soc/fsl/fsl_asrc_m2m.c| 791 4 files changed, 802 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..bff9c6bda344 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -8,6 +8,7 @@ config SND_SOC_FSL_ASRC depends on HAS_DMA select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_COMPRESS_ACCEL help Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) support for the Freescale CPUs. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ad97244b5cc3..d656a9ab54e3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o -snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 91dad736a969..63b4bee370e3 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -58,6 +58,7 @@ struct fsl_asrc_m2m_cap { * @buf_len: buffer length of m2m * @dma_buffer: buffer pointers * @first_convert: start of conversion + * @ratio_mod_flag: flag for new ratio modifier * @ratio_mod: ratio modification */ struct fsl_asrc_pair { @@ -82,6 +83,7 @@ struct fsl_asrc_pair { unsigned int buf_len[2]; struct snd_dma_buffer dma_buffer[2]; unsigned int first_convert; + bool ratio_mod_flag; unsigned int ratio_mod; }; @@ -96,6 +98,7 @@ struct fsl_asrc_pair { * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral * @spba_clk: SPBA clock (optional, depending on SoC design) + * @card: compress sound card * @lock: spin lock for resource protection * @pair: pair pointers * @channel_avail: non-occupied channel numbers @@ -129,6 +132,7 @@ struct fsl_asrc { struct clk *mem_clk; struct clk *ipg_clk; struct clk *spba_clk; + struct snd_card *card; spinlock_t lock; /* spin lock for resource protection */ struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; @@ -164,4 +168,9 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; +int fsl_asrc_m2m_init(struct fsl_asrc *asrc); +void fsl_asrc_m2m_exit(struct fsl_asrc *asrc); +int fsl_asrc_m2m_resume(struct fsl_asrc *asrc); +int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc); + #endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c new file mode 100644 index ..df09b3cce232 --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +// Copyright (C) 2019-2024 NXP +// +// Freescale ASRC Memory to Memory (M2M) driver + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_asrc_common.h" + +#define DIR_STR(dir) (dir) == IN ? "in" : "out" + +#define ASRC_xPUT_DMA_CALLBACK(dir) \ + (((dir) == IN) ? asrc_input_dma_callback \ + : asrc_output_dma_callback) + +/* Maximum output and capture buffer size */ +#define ASRC_M2M_BUFFER_SIZE (512 * 1024) + +/* Maximum output and capture period size */ +#define ASRC_M2M_PERIOD_SIZE (48 * 1024) + +#define ASRC_OUTPUT_FORMAT 0x8001 +#define ASRC_OUTPUT_RATE 0x8002 +#define ASRC_RATIO_MOD 0x8003 + +/* dma complete callback */ +static void asrc_input_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[IN]); +} + +/* dma complete callback */ +static void asrc_output_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[OUT]); +} + +/** + *asrc_read_last_fifo: read all the remaining data from FIFO + *@pair: Structure pointer of fsl_asrc_pair + *@dma_vaddr: virtual address of captu
[RFC PATCH v2 5/6] ASoC: fsl_asrc: register m2m platform device
Register m2m platform device, that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_asrc.c | 37 + 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 01e3af5b1bea..5d88abd905a5 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1381,6 +1381,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_get_sync; } + ret = fsl_asrc_m2m_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_get_sync: @@ -1393,6 +1399,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) static void fsl_asrc_remove(struct platform_device *pdev) { + struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(asrc); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) fsl_asrc_runtime_suspend(&pdev->dev); @@ -1494,10 +1504,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(asrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(asrc); + return ret; +} + static const struct dev_pm_ops fsl_asrc_pm = { - SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { @@ -1535,7 +1564,7 @@ static struct platform_driver fsl_asrc_driver = { .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, - .pm = &fsl_asrc_pm, + .pm = pm_ptr(&fsl_asrc_pm), }, }; module_platform_driver(fsl_asrc_driver); -- 2.34.1
[RFC PATCH v2 3/6] ASoC: fsl_easrc: define functions for memory to memory usage
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 --- sound/soc/fsl/fsl_easrc.c | 226 ++ sound/soc/fsl/fsl_easrc.h | 4 + 2 files changed, 230 insertions(+) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 962f30912091..959a8e2dd716 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1861,6 +1861,222 @@ 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_
[RFC PATCH v2 2/6] ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step 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 --- sound/soc/fsl/fsl_asrc.c| 139 sound/soc/fsl/fsl_asrc.h| 2 + sound/soc/fsl/fsl_asrc_common.h | 59 ++ 3 files changed, 200 insertions(+) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b793263291dc..01e3af5b1bea 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1063,6 +1063,136 @@ 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_prepare(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; + } + + pair->first_convert = 1; + + return 0; +} + +static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair) +{ + if (pair->first_convert) { + fsl_asrc_start_pair(pair); + pair->first_convert = 0; + } + /* +* 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(struct fsl_asrc_pair *pair) +{ + if (!pair->first_convert) { + fsl_asrc_stop_pair(pair); + pair->first_convert = 1; + } + + 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_get_cap(struct fsl_asrc_m2m_cap *cap) +{ + cap->fmt_in = FSL_ASRC_FORMATS; + cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8; + cap->rate_in = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_5512; + cap->rat
[RFC PATCH v2 0/6] ASoC: fsl: add memory to memory function for ASRC
This function is base on the accelerator implementation for compress API: https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ Audio signal processing also has the requirement for memory to memory similar as Video. This asrc memory to memory (memory ->asrc->memory) case is a non real time use case. User fills the input buffer to the asrc module, after conversion, then asrc sends back the output buffer to user. So it is not a traditional ALSA playback and capture case. Because we had implemented the "memory -> asrc ->i2s device-> codec" use case in ALSA. Now the "memory->asrc->memory" needs to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining the code to make it can be shared by the "memory->asrc->memory" driver. Other change is to add memory to memory support for two kinds of i.MX ASRC modules. changes in v2: - Remove the changes in compress API - drop the SNDRV_COMPRESS_SRC_RATIO_MOD - drop the SND_AUDIOCODEC_SRC and struct snd_dec_src - define private metadata key value ASRC_OUTPUT_FORMAT/ASRC_OUTPUT_RATE/ASRC_RATIO_MOD Shengjiu Wang (6): ALSA: compress: reserve space in snd_compr_metadata.key for private usage ASoC: fsl_asrc: define functions for memory to memory usage ASoC: fsl_easrc: define functions for memory to memory usage ASoC: fsl_asrc_m2m: Add memory to memory function ASoC: fsl_asrc: register m2m platform device ASoC: fsl_easrc: register m2m platform device include/uapi/sound/compress_offload.h | 2 +- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile| 2 +- sound/soc/fsl/fsl_asrc.c | 176 +- sound/soc/fsl/fsl_asrc.h | 2 + sound/soc/fsl/fsl_asrc_common.h | 68 +++ sound/soc/fsl/fsl_asrc_m2m.c | 791 ++ sound/soc/fsl/fsl_easrc.c | 259 - sound/soc/fsl/fsl_easrc.h | 4 + 9 files changed, 1297 insertions(+), 8 deletions(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c -- 2.34.1
[RFC PATCH v2 1/6] ALSA: compress: reserve space in snd_compr_metadata.key for private usage
Reserve the key value which is larger than 0x8000 for driver private usage. Driver may define its own key values which are not public in ALSA header Signed-off-by: Shengjiu Wang --- include/uapi/sound/compress_offload.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 98772b0cbcb7..7e9190538df2 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -120,7 +120,7 @@ enum sndrv_compress_encoder { /** * struct snd_compr_metadata - compressed stream metadata - * @key: key id + * @key: key id, value larger than 0x8000 reserved for driver private usage * @value: key value */ struct snd_compr_metadata { -- 2.34.1
Re: [RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
On Wed, Aug 14, 2024 at 5:40 PM Pierre-Louis Bossart wrote: > > > > Yes, to go further, I think we can use SND_AUDIOCODEC_PCM, then > > the SRC type will be dropped. > > sounds good. > > > But my understanding of the control means the .set_metadata() API, right? > > As I said, the output rate, output format, and ratio modifier are applied to > > the instances of ASRC, which is the snd_compr_stream in driver. > > so only the .set_metadata() API can be used for these purposes. > > Humm, this is more controversial. > > The term 'metadata' really referred to known information present in > headers or additional ID3 tags and not in the compressed file itself. > The .set_metadata was assumed to be called ONCE before decoding. > > But here you have a need to update the ratio modifier on a regular basis > to compensate for the drift. This isn't what this specific callback was > designed for. We could change and allow this callback to be used > multiple times, but then this could create problems for existing > implementations which cannot deal with modified metadata on the fly. .set_metadata can be called multi times now, no need to change currently. > > And then there's the problem of defining a 'key' for the metadata. the > definition of the key is a u32, so there's plenty of space for different > implementations, but a collision is possible. We'd need an agreement on > how to allocate keys to different solutions without changing the header > file for every implementation. Can we define a private space for each case? For example the key larger than 0x8000 is private, each driver can define it by themself? > > It sounds like we'd need a 'runtime params' callback - unless there's a > better trick to tie the control and compress layers? >
Re: [RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
On Mon, Aug 12, 2024 at 9:44 PM Pierre-Louis Bossart wrote: > > > > On 8/12/24 15:31, Jaroslav Kysela wrote: > > On 12. 08. 24 12:24, Shengjiu Wang wrote: > >> On Fri, Aug 9, 2024 at 10:01 PM Jaroslav Kysela wrote: > >>> > >>> On 09. 08. 24 14:52, Pierre-Louis Bossart wrote: > >>> > >>>>> And metadata > >>>>> ioctl can be called many times which can meet the ratio modifier > >>>>> requirement (ratio may be drift on the fly) > >>>> > >>>> Interesting, that's yet another way of handling the drift with > >>>> userspace > >>>> modifying the ratio dynamically. That's different to what I've seen > >>>> before. > >>> > >>> Note that the "timing" is managed by the user space with this scheme. > >>> > >>>>> And compress API uses codec as the unit for capability query and > >>>>> parameter setting, So I think need to define "SND_AUDIOCODEC_SRC' > >>>>> and 'struct snd_dec_src', for the 'snd_dec_src' just defined output > >>>>> format and output rate, channels definition just reuse the > >>>>> snd_codec.ch_in. > >>>> > >>>> The capability query is an interesting point as well, it's not clear > >>>> how > >>>> to expose to userspace what this specific implementation can do, while > >>>> at the same time *requiring* userpace to update the ratio dynamically. > >>>> For something like this to work, userspace needs to have pre-existing > >>>> information on how the SRC works. > >>> > >>> Yes, it's about abstraction. The user space wants to push data, read > >>> data back > >>> converted to the target rate and eventually modify the drift using a > >>> control > >>> managing clocks using own way. We can eventually assume, that if this > >>> control > >>> does not exist, the drift cannot be controlled. Also, nice thing is > >>> that the > >>> control has min and max values (range), so driver can specify the > >>> drift range, > >>> too. > >>> > >>> And again, look to "PCM Rate Shift 10" control implementation in > >>> sound/drivers/aloop.c. It would be nice to have the base offset for the > >>> shift/drift/pitch value standardized. > >> > >> Thanks. > >> > >> But the ASRC driver I implemented is different, I just register one sound > >> card, one device/subdevice. but the ASRC hardware support 4 instances > >> together, so user can open the card device 4 times to create 4 instances > >> then the controls can only bind with compress streams. > > > > It's just a reason to add the subdevice code for the compress offload > > layer like we have in other APIs for overall consistency. I'll try to > > work on this. > > I thought this was supported already? I remember there was a request to > enable more than one compressed stream for enhanced cross-fade support > with different formats? That isn't supported with the single-device + > PARTIAL_DRAIN method. > > Vinod? > > >> I think I can remove the 'SNDRV_COMPRESS_SRC_RATIO_MOD', > > > > Yes. > > > >> Only define a private type for driver, which means only the ASRC driver > >> and its user application know the type. > > > > The control API should be used for this IMHO. > > Agree, this would be a 'clean' split where the compress API is used for > the data parts and the control parts used otherwise to alter the ratio > or whatever else is needed. > > >> For the change in 'include/uapi/sound/compress_params.h", should I > >> keep them, is there any other suggestion for them? > > You can add the SRC type but if you use a control for the parameters you > don't need to add anything for the encoder options, do you? > Yes, to go further, I think we can use SND_AUDIOCODEC_PCM, then the SRC type will be dropped. But my understanding of the control means the .set_metadata() API, right? As I said, the output rate, output format, and ratio modifier are applied to the instances of ASRC, which is the snd_compr_stream in driver. so only the .set_metadata() API can be used for these purposes. Best regards Shengjiu Wang
Re: [RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
On Fri, Aug 9, 2024 at 10:01 PM Jaroslav Kysela wrote: > > On 09. 08. 24 14:52, Pierre-Louis Bossart wrote: > > >> And metadata > >> ioctl can be called many times which can meet the ratio modifier > >> requirement (ratio may be drift on the fly) > > > > Interesting, that's yet another way of handling the drift with userspace > > modifying the ratio dynamically. That's different to what I've seen before. > > Note that the "timing" is managed by the user space with this scheme. > > >> And compress API uses codec as the unit for capability query and > >> parameter setting, So I think need to define "SND_AUDIOCODEC_SRC' > >> and 'struct snd_dec_src', for the 'snd_dec_src' just defined output > >> format and output rate, channels definition just reuse the snd_codec.ch_in. > > > > The capability query is an interesting point as well, it's not clear how > > to expose to userspace what this specific implementation can do, while > > at the same time *requiring* userpace to update the ratio dynamically. > > For something like this to work, userspace needs to have pre-existing > > information on how the SRC works. > > Yes, it's about abstraction. The user space wants to push data, read data back > converted to the target rate and eventually modify the drift using a control > managing clocks using own way. We can eventually assume, that if this control > does not exist, the drift cannot be controlled. Also, nice thing is that the > control has min and max values (range), so driver can specify the drift range, > too. > > And again, look to "PCM Rate Shift 10" control implementation in > sound/drivers/aloop.c. It would be nice to have the base offset for the > shift/drift/pitch value standardized. Thanks. But the ASRC driver I implemented is different, I just register one sound card, one device/subdevice. but the ASRC hardware support 4 instances together, so user can open the card device 4 times to create 4 instances then the controls can only bind with compress streams. I think I can remove the 'SNDRV_COMPRESS_SRC_RATIO_MOD', Only define a private type for driver, which means only the ASRC driver and its user application know the type. For the change in 'include/uapi/sound/compress_params.h", should I keep them, is there any other suggestion for them? Best regards Shengjiu Wang > > Jaroslav > > -- > Jaroslav Kysela > Linux Sound Maintainer; ALSA Project; Red Hat, Inc. >
Re: [RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
tation) used behind may > > depend on the hardware/driver capabilities. > > Indeed there is a possibility that the parameters are high-level, but > that would require firmware or hardware to be able to generate actual > coefficients from those parameters. That usually requires some advanced > math which isn't necessarily obvious to implement with fixed-point hardware. > > > From my view, the really special cases may be handled as black box, but > > others like (A)SRC should follow some well-defined abstraction IMHO to > > not force user space to handle all special cases. > > I am not against the high-level abstractions, e.g. along the lines of > what Android defined: > https://developer.android.com/reference/android/media/audiofx/AudioEffect > > That's not sufficient however, we also need to make sure there's an > ability to provide pre-computed coefficients in an opaque manner for > processing that doesn't fit in the well-defined cases. In practice there > are very few 3rd party IP that fits in well-defined cases, everyone has > secret-sauce parameters and options. Appreciate the discussion. Let me explain the reason for the change: Why I use the metadata ioctl is because the ALSA controls are binding to the sound card. What I want is the controls can be bound to snd_compr_stream, because the ASRC compress sound card can support multi instances ( the ASRC can support multi conversion in parallel). The ALSA controls can't be used for this case, the only choice in current compress API is metadata ioctl. And metadata ioctl can be called many times which can meet the ratio modifier requirement (ratio may be drift on the fly) And compress API uses codec as the unit for capability query and parameter setting, So I think need to define "SND_AUDIOCODEC_SRC' and 'struct snd_dec_src', for the 'snd_dec_src' just defined output format and output rate, channels definition just reuse the snd_codec.ch_in. I understand your concern, but there seems no better option. If you have, please guide me. Thanks. Best regards Shengjiu Wang
Re: [RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
On Tue, Aug 6, 2024 at 7:25 PM Pierre-Louis Bossart wrote: > > > > On 8/6/24 12:26, Shengjiu Wang wrote: > > Add Sample Rate Converter(SRC) codec support, define the output > > format and rate for SRC. > > > > Signed-off-by: Shengjiu Wang > > --- > > include/uapi/sound/compress_offload.h | 2 ++ > > include/uapi/sound/compress_params.h | 9 - > > 2 files changed, 10 insertions(+), 1 deletion(-) > > > > diff --git a/include/uapi/sound/compress_offload.h > > b/include/uapi/sound/compress_offload.h > > index 98772b0cbcb7..8b2b72f94e26 100644 > > --- a/include/uapi/sound/compress_offload.h > > +++ b/include/uapi/sound/compress_offload.h > > @@ -112,10 +112,12 @@ struct snd_compr_codec_caps { > > * end of the track > > * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at > > the > > * beginning of the track > > + * @SNDRV_COMPRESS_SRC_RATIO_MOD: Resampling Ratio Modifier for sample > > rate converter > > */ > > enum sndrv_compress_encoder { > > SNDRV_COMPRESS_ENCODER_PADDING = 1, > > SNDRV_COMPRESS_ENCODER_DELAY = 2, > > + SNDRV_COMPRESS_SRC_RATIO_MOD = 3, > > }; > > this sounds wrong to me. The sample rate converter is not an "encoder", > and the properties for padding/delay are totally specific to an encoder > function. There is only decoder and encoder definition for compress, I know it is difficult to add SRC to encoder or decoder classification, SRC is a Post Processing. I hope you can have a recommandation. Thanks. Best regards Shengjiu Wang > > The other point is that I am not sure how standard this ratio_mod > parameter is. This could be totally specific to a specific > implementation, and another ASRC might have different parameters. > > > > > /** > > diff --git a/include/uapi/sound/compress_params.h > > b/include/uapi/sound/compress_params.h > > index ddc77322d571..0843773ea6b4 100644 > > --- a/include/uapi/sound/compress_params.h > > +++ b/include/uapi/sound/compress_params.h > > @@ -43,7 +43,8 @@ > > #define SND_AUDIOCODEC_BESPOKE ((__u32) 0x000E) > > #define SND_AUDIOCODEC_ALAC ((__u32) 0x000F) > > #define SND_AUDIOCODEC_APE ((__u32) 0x0010) > > -#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APE > > +#define SND_AUDIOCODEC_SRC ((__u32) 0x0011) > > +#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_SRC > > I am not sure this is wise to change such definitions? > > > > /* > > * Profile and modes are listed with bit masks. This allows for a > > @@ -324,6 +325,11 @@ struct snd_dec_ape { > > __u32 seek_table_present; > > } __attribute__((packed, aligned(4))); > > > > +struct snd_dec_src { > > + __u32 format_out; > > + __u32 rate_out; > > +} __attribute__((packed, aligned(4))); > > Again I am not sure how standard those parameters are, and even if they > were if their representation is reusable. > > And the compressed API has a good split between encoders and decoders, I > am not sure how an SRC can be classified as either. > > > union snd_codec_options { > > struct snd_enc_wma wma; > > struct snd_enc_vorbis vorbis; > > @@ -334,6 +340,7 @@ union snd_codec_options { > > struct snd_dec_wma wma_d; > > struct snd_dec_alac alac_d; > > struct snd_dec_ape ape_d; > > + struct snd_dec_src src; > > } __attribute__((packed, aligned(4))); > > > > /** struct snd_codec_desc - description of codec capabilities >
[RFC PATCH 6/6] ASoC: fsl_easrc: register m2m platform device
Register m2m platform device,that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_easrc.c | 33 +++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 959a8e2dd716..98adbae082fa 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -2202,6 +2202,12 @@ static int fsl_easrc_probe(struct platform_device *pdev) goto err_pm_disable; } + ret = fsl_asrc_m2m_init(easrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_disable: @@ -2211,6 +2217,10 @@ static int fsl_easrc_probe(struct platform_device *pdev) static void fsl_easrc_remove(struct platform_device *pdev) { + struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(easrc); + pm_runtime_disable(&pdev->dev); } @@ -2311,10 +2321,29 @@ static int fsl_easrc_runtime_resume(struct device *dev) return ret; } +static int fsl_easrc_suspend(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(easrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_easrc_resume(struct device *dev) +{ + struct fsl_asrc *easrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(easrc); + return ret; +} + static const struct dev_pm_ops fsl_easrc_pm_ops = { RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume) }; static struct platform_driver fsl_easrc_driver = { -- 2.34.1
[RFC PATCH 5/6] ASoC: fsl_asrc: register m2m platform device
Register m2m platform device, that user can use M2M feature. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_asrc.c | 37 + 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 01e3af5b1bea..5d88abd905a5 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1381,6 +1381,12 @@ static int fsl_asrc_probe(struct platform_device *pdev) goto err_pm_get_sync; } + ret = fsl_asrc_m2m_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init m2m device %d\n", ret); + return ret; + } + return 0; err_pm_get_sync: @@ -1393,6 +1399,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) static void fsl_asrc_remove(struct platform_device *pdev) { + struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev); + + fsl_asrc_m2m_exit(asrc); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) fsl_asrc_runtime_suspend(&pdev->dev); @@ -1494,10 +1504,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } +static int fsl_asrc_suspend(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + fsl_asrc_m2m_suspend(asrc); + ret = pm_runtime_force_suspend(dev); + return ret; +} + +static int fsl_asrc_resume(struct device *dev) +{ + struct fsl_asrc *asrc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + fsl_asrc_m2m_resume(asrc); + return ret; +} + static const struct dev_pm_ops fsl_asrc_pm = { - SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { @@ -1535,7 +1564,7 @@ static struct platform_driver fsl_asrc_driver = { .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, - .pm = &fsl_asrc_pm, + .pm = pm_ptr(&fsl_asrc_pm), }, }; module_platform_driver(fsl_asrc_driver); -- 2.34.1
[RFC PATCH 4/6] ASoC: fsl_asrc_m2m: Add memory to memory function
Implement the ASRC memory to memory function using the compress framework, user can use this function with compress ioctl interface. This feature can be shared by ASRC and EASRC drivers Signed-off-by: Shengjiu Wang --- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile | 2 +- sound/soc/fsl/fsl_asrc_common.h | 9 + sound/soc/fsl/fsl_asrc_m2m.c| 769 4 files changed, 780 insertions(+), 1 deletion(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfef..bff9c6bda344 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -8,6 +8,7 @@ config SND_SOC_FSL_ASRC depends on HAS_DMA select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_COMPRESS_ACCEL help Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) support for the Freescale CPUs. diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ad97244b5cc3..d656a9ab54e3 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o # Freescale SSI/DMA/SAI/SPDIF Support snd-soc-fsl-audmix-y := fsl_audmix.o snd-soc-fsl-asoc-card-y := fsl-asoc-card.o -snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o +snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o snd-soc-fsl-sai-y := fsl_sai.o snd-soc-fsl-ssi-y := fsl_ssi.o diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 91dad736a969..63b4bee370e3 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -58,6 +58,7 @@ struct fsl_asrc_m2m_cap { * @buf_len: buffer length of m2m * @dma_buffer: buffer pointers * @first_convert: start of conversion + * @ratio_mod_flag: flag for new ratio modifier * @ratio_mod: ratio modification */ struct fsl_asrc_pair { @@ -82,6 +83,7 @@ struct fsl_asrc_pair { unsigned int buf_len[2]; struct snd_dma_buffer dma_buffer[2]; unsigned int first_convert; + bool ratio_mod_flag; unsigned int ratio_mod; }; @@ -96,6 +98,7 @@ struct fsl_asrc_pair { * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral * @spba_clk: SPBA clock (optional, depending on SoC design) + * @card: compress sound card * @lock: spin lock for resource protection * @pair: pair pointers * @channel_avail: non-occupied channel numbers @@ -129,6 +132,7 @@ struct fsl_asrc { struct clk *mem_clk; struct clk *ipg_clk; struct clk *spba_clk; + struct snd_card *card; spinlock_t lock; /* spin lock for resource protection */ struct fsl_asrc_pair *pair[PAIR_CTX_NUM]; @@ -164,4 +168,9 @@ struct fsl_asrc { #define DRV_NAME "fsl-asrc-dai" extern struct snd_soc_component_driver fsl_asrc_component; +int fsl_asrc_m2m_init(struct fsl_asrc *asrc); +void fsl_asrc_m2m_exit(struct fsl_asrc *asrc); +int fsl_asrc_m2m_resume(struct fsl_asrc *asrc); +int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc); + #endif /* _FSL_ASRC_COMMON_H */ diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c new file mode 100644 index ..7be5fb725afc --- /dev/null +++ b/sound/soc/fsl/fsl_asrc_m2m.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +// Copyright (C) 2019-2024 NXP +// +// Freescale ASRC Memory to Memory (M2M) driver + +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_asrc_common.h" + +#define DIR_STR(dir) (dir) == IN ? "in" : "out" + +#define ASRC_xPUT_DMA_CALLBACK(dir) \ + (((dir) == IN) ? asrc_input_dma_callback \ + : asrc_output_dma_callback) + +/* Maximum output and capture buffer size */ +#define ASRC_M2M_BUFFER_SIZE (512 * 1024) + +/* Maximum output and capture period size */ +#define ASRC_M2M_PERIOD_SIZE (48 * 1024) + +/* dma complete callback */ +static void asrc_input_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[IN]); +} + +/* dma complete callback */ +static void asrc_output_dma_callback(void *data) +{ + struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data; + + complete(&pair->complete[OUT]); +} + +/** + *asrc_read_last_fifo: read all the remaining data from FIFO + *@pair: Structure pointer of fsl_asrc_pair + *@dma_vaddr: virtual address of capture buffer + *@length: payload length of capture buffer + */ +static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, void *dma_vaddr, u32 *length) +{ + struct fsl_asrc *asrc = pair->asrc; + enum asrc_pair_index index = pair->index; + u32 i, reg, size, t_size = 0, width; + u32 *reg32
[RFC PATCH 3/6] ASoC: fsl_easrc: define functions for memory to memory usage
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 --- sound/soc/fsl/fsl_easrc.c | 226 ++ sound/soc/fsl/fsl_easrc.h | 4 + 2 files changed, 230 insertions(+) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 962f30912091..959a8e2dd716 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1861,6 +1861,222 @@ 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_
[RFC PATCH 2/6] ASoC: fsl_asrc: define functions for memory to memory usage
ASRC can be used on memory to memory case, define several functions for m2m usage. m2m_prepare: prepare for the start step m2m_start: the start step m2m_unprepare: unprepare for stop step, optional m2m_stop: stop step 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 --- sound/soc/fsl/fsl_asrc.c| 139 sound/soc/fsl/fsl_asrc.h| 2 + sound/soc/fsl/fsl_asrc_common.h | 59 ++ 3 files changed, 200 insertions(+) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index b793263291dc..01e3af5b1bea 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1063,6 +1063,136 @@ 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_prepare(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; + } + + pair->first_convert = 1; + + return 0; +} + +static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair) +{ + if (pair->first_convert) { + fsl_asrc_start_pair(pair); + pair->first_convert = 0; + } + /* +* 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(struct fsl_asrc_pair *pair) +{ + if (!pair->first_convert) { + fsl_asrc_stop_pair(pair); + pair->first_convert = 1; + } + + 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_get_cap(struct fsl_asrc_m2m_cap *cap) +{ + cap->fmt_in = FSL_ASRC_FORMATS; + cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8; + cap->rate_in = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_5512; + cap->rat
[RFC PATCH 0/6] ASoC: fsl: add memory to memory function for ASRC
This function is base on the accelerator implementation for compress API: https://patchwork.kernel.org/project/alsa-devel/patch/20240731083843.59911-1-pe...@perex.cz/ Audio signal processing also has the requirement for memory to memory similar as Video. This asrc memory to memory (memory ->asrc->memory) case is a non real time use case. User fills the input buffer to the asrc module, after conversion, then asrc sends back the output buffer to user. So it is not a traditional ALSA playback and capture case. Because we had implemented the "memory -> asrc ->i2s device-> codec" use case in ALSA. Now the "memory->asrc->memory" needs to reuse the code in asrc driver, so the patch 1 and patch 2 is for refining the code to make it can be shared by the "memory->asrc->memory" driver. Other change is to add memory to memory support for two kinds of i.MX ASRC modules. Shengjiu Wang (6): ALSA: compress: add Sample Rate Converter codec support ASoC: fsl_asrc: define functions for memory to memory usage ASoC: fsl_easrc: define functions for memory to memory usage ASoC: fsl_asrc_m2m: Add memory to memory function ASoC: fsl_asrc: register m2m platform device ASoC: fsl_easrc: register m2m platform device include/uapi/sound/compress_offload.h | 2 + include/uapi/sound/compress_params.h | 9 +- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/Makefile| 2 +- sound/soc/fsl/fsl_asrc.c | 176 +- sound/soc/fsl/fsl_asrc.h | 2 + sound/soc/fsl/fsl_asrc_common.h | 68 +++ sound/soc/fsl/fsl_asrc_m2m.c | 769 ++ sound/soc/fsl/fsl_easrc.c | 259 - sound/soc/fsl/fsl_easrc.h | 4 + 10 files changed, 1284 insertions(+), 8 deletions(-) create mode 100644 sound/soc/fsl/fsl_asrc_m2m.c -- 2.34.1
[RFC PATCH 1/6] ALSA: compress: add Sample Rate Converter codec support
Add Sample Rate Converter(SRC) codec support, define the output format and rate for SRC. Signed-off-by: Shengjiu Wang --- include/uapi/sound/compress_offload.h | 2 ++ include/uapi/sound/compress_params.h | 9 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index 98772b0cbcb7..8b2b72f94e26 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -112,10 +112,12 @@ struct snd_compr_codec_caps { * end of the track * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the * beginning of the track + * @SNDRV_COMPRESS_SRC_RATIO_MOD: Resampling Ratio Modifier for sample rate converter */ enum sndrv_compress_encoder { SNDRV_COMPRESS_ENCODER_PADDING = 1, SNDRV_COMPRESS_ENCODER_DELAY = 2, + SNDRV_COMPRESS_SRC_RATIO_MOD = 3, }; /** diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index ddc77322d571..0843773ea6b4 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -43,7 +43,8 @@ #define SND_AUDIOCODEC_BESPOKE ((__u32) 0x000E) #define SND_AUDIOCODEC_ALAC ((__u32) 0x000F) #define SND_AUDIOCODEC_APE ((__u32) 0x0010) -#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_APE +#define SND_AUDIOCODEC_SRC ((__u32) 0x0011) +#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_SRC /* * Profile and modes are listed with bit masks. This allows for a @@ -324,6 +325,11 @@ struct snd_dec_ape { __u32 seek_table_present; } __attribute__((packed, aligned(4))); +struct snd_dec_src { + __u32 format_out; + __u32 rate_out; +} __attribute__((packed, aligned(4))); + union snd_codec_options { struct snd_enc_wma wma; struct snd_enc_vorbis vorbis; @@ -334,6 +340,7 @@ union snd_codec_options { struct snd_dec_wma wma_d; struct snd_dec_alac alac_d; struct snd_dec_ape ape_d; + struct snd_dec_src src; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities -- 2.34.1
[PATCH 2/2] ASoC: fsl_micfil: Differentiate register access permission for platforms
On i.MX9x platforms, the REG_MICFIL_FSYNC_CTRL, REG_MICFIL_VERID, REG_MICFIL_PARAM are added, but they are not existed on i.MX8x platforms. Use the existed micfil->soc->use_verid to distinguish the access permission for these platforms. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 18 ++ 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 96a6b88d0d67..22b240a70ad4 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -855,6 +855,8 @@ static const struct reg_default fsl_micfil_reg_defaults[] = { static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) { + struct fsl_micfil *micfil = dev_get_drvdata(dev); + switch (reg) { case REG_MICFIL_CTRL1: case REG_MICFIL_CTRL2: @@ -872,9 +874,6 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: - case REG_MICFIL_FSYNC_CTRL: - case REG_MICFIL_VERID: - case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: @@ -883,6 +882,12 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_VAD0_NDATA: case REG_MICFIL_VAD0_ZCD: return true; + case REG_MICFIL_FSYNC_CTRL: + case REG_MICFIL_VERID: + case REG_MICFIL_PARAM: + if (micfil->soc->use_verid) + return true; + fallthrough; default: return false; } @@ -890,6 +895,8 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) { + struct fsl_micfil *micfil = dev_get_drvdata(dev); + switch (reg) { case REG_MICFIL_CTRL1: case REG_MICFIL_CTRL2: @@ -899,7 +906,6 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DC_CTRL: case REG_MICFIL_OUT_CTRL: case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ - case REG_MICFIL_FSYNC_CTRL: case REG_MICFIL_VAD0_CTRL1: case REG_MICFIL_VAD0_CTRL2: case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ @@ -907,6 +913,10 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) case REG_MICFIL_VAD0_NCONFIG: case REG_MICFIL_VAD0_ZCD: return true; + case REG_MICFIL_FSYNC_CTRL: + if (micfil->soc->use_verid) + return true; + fallthrough; default: return false; } -- 2.34.1
[PATCH 1/2] ASoC: fsl_micfil: Expand the range of FIFO watermark mask
On the i.MX9x platforms, the mask of FIFO watermark is 0x1F, on i.MX8x platforms, the mask of FIFO watermark is 0X7. So use the mask 0x1F for all platforms to make them compatible. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_micfil.c | 2 +- sound/soc/fsl/fsl_micfil.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 0d37edb70261..96a6b88d0d67 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -831,7 +831,7 @@ static const struct reg_default fsl_micfil_reg_defaults[] = { {REG_MICFIL_CTRL1, 0x}, {REG_MICFIL_CTRL2, 0x}, {REG_MICFIL_STAT, 0x}, - {REG_MICFIL_FIFO_CTRL, 0x0007}, + {REG_MICFIL_FIFO_CTRL, 0x001F}, {REG_MICFIL_FIFO_STAT, 0x}, {REG_MICFIL_DATACH0,0x}, {REG_MICFIL_DATACH1,0x}, diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index c6b902ba0a53..b7798a7cbf2a 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -72,7 +72,7 @@ #define MICFIL_STAT_CHXF(ch) BIT(ch) /* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ -#define MICFIL_FIFO_CTRL_FIFOWMK GENMASK(2, 0) +#define MICFIL_FIFO_CTRL_FIFOWMK GENMASK(4, 0) /* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ #define MICFIL_FIFO_STAT_FIFOX_OVER(ch)BIT(ch) -- 2.34.1
[PATCH 0/2] ASoC: fsl_micfil: Check the difference for i.MX8 and i.MX9
There are some register difference for i.MX8 and i.MX9 REG_MICFIL_FIFO_CTRL definition is updated. REG_MICFIL_FSYNC_CTRL, REG_MICFIL_VERID, REG_MICFIL_PARAM are added from i.MX9 Shengjiu Wang (2): ASoC: fsl_micfil: Expand the range of FIFO watermark mask ASoC: fsl_micfil: Differentiate register access permission for platforms sound/soc/fsl/fsl_micfil.c | 20 +++- sound/soc/fsl/fsl_micfil.h | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) -- 2.34.1
[PATCH] ASoC: fsl-asoc-card: Dynamically allocate memory for snd_soc_dai_link_components
The static snd_soc_dai_link_components cause conflict for multiple instances of this generic driver. For example, when there is wm8962 and SPDIF case enabled together, the contaminated snd_soc_dai_link_components will cause another device probe fail. Fixes: 6d174cc4f224 ("ASoC: fsl-asoc-card: merge spdif support from imx-spdif.c") Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl-asoc-card.c | 46 ++- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 82df887b3af5..f6c3aeff0d8e 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -306,27 +306,12 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -SND_SOC_DAILINK_DEFS(hifi, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -SND_SOC_DAILINK_DEFS(hifi_fe, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_DUMMY()), - DAILINK_COMP_ARRAY(COMP_EMPTY())); - -SND_SOC_DAILINK_DEFS(hifi_be, - DAILINK_COMP_ARRAY(COMP_EMPTY()), - DAILINK_COMP_ARRAY(COMP_EMPTY(), COMP_EMPTY())); - static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { /* Default ASoC DAI Link*/ { .name = "HiFi", .stream_name = "HiFi", .ops = &fsl_asoc_card_ops, - SND_SOC_DAILINK_REG(hifi), }, /* DPCM Link between Front-End and Back-End (Optional) */ { @@ -335,7 +320,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { .dpcm_playback = 1, .dpcm_capture = 1, .dynamic = 1, - SND_SOC_DAILINK_REG(hifi_fe), }, { .name = "HiFi-ASRC-BE", @@ -345,7 +329,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { .dpcm_playback = 1, .dpcm_capture = 1, .no_pcm = 1, - SND_SOC_DAILINK_REG(hifi_be), }, }; @@ -637,6 +620,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct platform_device *cpu_pdev; struct fsl_asoc_card_priv *priv; struct device *codec_dev[2] = { NULL, NULL }; + struct snd_soc_dai_link_component *dlc; const char *codec_dai_name[2]; const char *codec_dev_name[2]; u32 asrc_fmt = 0; @@ -717,7 +701,35 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) memcpy(priv->dai_link, fsl_asoc_card_dai, sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); + /* +* "Default ASoC DAI Link": 1 cpus, 2 codecs, 1 platforms +* "DPCM Link Front-End": 1 cpus, 1 codecs (dummy), 1 platforms +* "DPCM Link Back-End": 1 cpus, 2 codecs +* totally 10 components +*/ + dlc = devm_kcalloc(&pdev->dev, 10, sizeof(*dlc), GFP_KERNEL); + if (!dlc) { + ret = -ENOMEM; + goto asrc_fail; + } + + priv->dai_link[0].cpus = &dlc[0]; + priv->dai_link[0].num_cpus = 1; + priv->dai_link[0].codecs = &dlc[1]; priv->dai_link[0].num_codecs = 1; + priv->dai_link[0].platforms = &dlc[3]; + priv->dai_link[0].num_platforms = 1; + + priv->dai_link[1].cpus = &dlc[4]; + priv->dai_link[1].num_cpus = 1; + priv->dai_link[1].codecs = &dlc[5]; + priv->dai_link[1].num_codecs = 0; /* dummy */ + priv->dai_link[1].platforms = &dlc[6]; + priv->dai_link[1].num_platforms = 1; + + priv->dai_link[2].cpus = &dlc[7]; + priv->dai_link[2].num_cpus = 1; + priv->dai_link[2].codecs = &dlc[8]; priv->dai_link[2].num_codecs = 1; priv->card.dapm_routes = audio_map; -- 2.34.1
Re: [PATCH] ASoC: fsl_xcvr: Improve suspend/resume flow in fsl_xcvr_trigger()
On Fri, Jun 28, 2024 at 5:44 PM Chancel Liu wrote: > > In the current flow all interrupts are disabled in runtime suspend > phase. However interrupts enablement only exists in fsl_xcvr_prepare(). > After resume fsl_xcvr_prepare() may not be called so it will cause all > interrupts still disabled even if resume from suspend. Interrupts > should be explictily enabled after resume. > > Also, DPATH reset setting only exists in fsl_xcvr_prepare(). After > resume from suspend DPATH should be reset otherwise there'll be channel > swap issue. > > Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Best regards Shengjiu Wang > --- > sound/soc/fsl/fsl_xcvr.c | 43 +--- > 1 file changed, 23 insertions(+), 20 deletions(-) > > diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c > index 337da46a2f90..bf9a4e90978e 100644 > --- a/sound/soc/fsl/fsl_xcvr.c > +++ b/sound/soc/fsl/fsl_xcvr.c > @@ -529,16 +529,6 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream > *substream, > break; > } > > - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, > -FSL_XCVR_IRQ_EARC_ALL, > FSL_XCVR_IRQ_EARC_ALL); > - if (ret < 0) { > - dev_err(dai->dev, "Error while setting IER0: %d\n", ret); > - return ret; > - } > - > - /* set DPATH RESET */ > - m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); > - v_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx); > ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, > v_ctl); > if (ret < 0) { > dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret); > @@ -679,6 +669,15 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream > *substream, int cmd, > case SNDRV_PCM_TRIGGER_START: > case SNDRV_PCM_TRIGGER_RESUME: > case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: > + /* set DPATH RESET */ > + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, > +FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), > +FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); > + if (ret < 0) { > + dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", > ret); > + return ret; > + } > + > if (tx) { > switch (xcvr->mode) { > case FSL_XCVR_MODE_EARC: > @@ -711,6 +710,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream > *substream, int cmd, > return ret; > } > > + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, > +FSL_XCVR_IRQ_EARC_ALL, > FSL_XCVR_IRQ_EARC_ALL); > + if (ret < 0) { > + dev_err(dai->dev, "Error while setting IER0: %d\n", > ret); > + return ret; > + } > + > /* clear DPATH RESET */ > ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, > FSL_XCVR_EXT_CTRL_DPTH_RESET(tx), > @@ -733,6 +739,13 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream > *substream, int cmd, > return ret; > } > > + ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, > +FSL_XCVR_IRQ_EARC_ALL, 0); > + if (ret < 0) { > + dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); > + return ret; > + } > + > if (tx) { > switch (xcvr->mode) { > case FSL_XCVR_MODE_SPDIF: > @@ -1411,16 +1424,6 @@ static int fsl_xcvr_runtime_suspend(struct device *dev) > struct fsl_xcvr *xcvr = dev_get_drvdata(dev); > int ret; > > - /* > -* Clear interrupts, when streams starts or resumes after > -* suspend, interrupts are enabled in prepare(), so no need > -* to enable interrupts in resume(). > -*/ > - ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, > -FSL_XCVR_IRQ_EARC_ALL, 0); > - if (ret < 0) > - dev_err(dev, "Failed to clear IER0: %d\n", ret); > - > if (!xcvr->soc_data->spdif_only) { > /* Assert M0+ reset */ > ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, > -- > 2.43.0 >
Re: [PATCH 2/2] ASoC: fsl_rpmsg: Add support for i.MX95 platform
On Wed, Jun 26, 2024 at 3:12 PM Chancel Liu wrote: > > Add compatible string and specific soc data to support rpmsg sound card > on i.MX95 platform. > > Signed-off-by: Chancel Liu Acked-by: Shengjiu Wang Best regards Shengjiu Wang > --- > sound/soc/fsl/fsl_rpmsg.c | 9 + > 1 file changed, 9 insertions(+) > > diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c > index bc41a0666856..467d6bc9f956 100644 > --- a/sound/soc/fsl/fsl_rpmsg.c > +++ b/sound/soc/fsl/fsl_rpmsg.c > @@ -175,6 +175,14 @@ static const struct fsl_rpmsg_soc_data imx93_data = { >SNDRV_PCM_FMTBIT_S32_LE, > }; > > +static const struct fsl_rpmsg_soc_data imx95_data = { > + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | > +SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | > +SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, > + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | > + SNDRV_PCM_FMTBIT_S32_LE, > +}; > + > static const struct of_device_id fsl_rpmsg_ids[] = { > { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data}, > { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data}, > @@ -182,6 +190,7 @@ static const struct of_device_id fsl_rpmsg_ids[] = { > { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data}, > { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data}, > { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data}, > + { .compatible = "fsl,imx95-rpmsg-audio", .data = &imx95_data}, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); > -- > 2.43.0 >
[PATCH 3/3] ASoC: imx-audmix: Split capture device for audmix
There will be three devices for this sound card, hw:x,0 is the playback device for one SAI, hw:x,1 is the playback device for another SAI, hw:x,2 is the capture device for audmix output. then capture device and playback device can be configured with different master/slave mode. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/imx-audmix.c | 79 ++ 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 2aeb18397bcb..6fbcf33fd0de 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -140,6 +140,13 @@ static const struct snd_soc_ops imx_audmix_be_ops = { .hw_params = imx_audmix_be_hw_params, }; +static const char *name[][3] = { + {"HiFi-AUDMIX-FE-0", "HiFi-AUDMIX-FE-1", "HiFi-AUDMIX-FE-2"}, + {"sai-tx", "sai-tx", "sai-rx"}, + {"AUDMIX-Playback-0", "AUDMIX-Playback-1", "CPU-Capture"}, + {"CPU-Playback", "CPU-Playback", "AUDMIX-Capture-0"}, +}; + static int imx_audmix_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -150,7 +157,7 @@ static int imx_audmix_probe(struct platform_device *pdev) struct imx_audmix *priv; int i, num_dai, ret; const char *fe_name_pref = "HiFi-AUDMIX-FE-"; - char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name; + char *be_name, *dai_name; if (pdev->dev.parent) { audmix_np = pdev->dev.parent->of_node; @@ -183,6 +190,7 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + num_dai += 1; priv->num_dai = 2 * num_dai; priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai, sizeof(struct snd_soc_dai_link), GFP_KERNEL); @@ -196,7 +204,7 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!priv->dai_conf) return -ENOMEM; - priv->num_dapm_routes = 3 * num_dai; + priv->num_dapm_routes = num_dai; priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes, sizeof(struct snd_soc_dapm_route), GFP_KERNEL); @@ -211,8 +219,12 @@ static int imx_audmix_probe(struct platform_device *pdev) if (!dlc) return -ENOMEM; - ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, -&args); + if (i == num_dai - 1) + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, 0, +&args); + else + ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i, +&args); if (ret < 0) { dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n"); return ret; @@ -226,20 +238,14 @@ static int imx_audmix_probe(struct platform_device *pdev) put_device(&cpu_pdev->dev); dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s", - fe_name_pref, args.np->full_name + 1); + fe_name_pref, args.np->full_name); if (!dai_name) return -ENOMEM; dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name); - if (i == 0) { + if (i == num_dai - 1) out_cpu_np = args.np; - capture_dai_name = - devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s", - dai_name, "CPU-Capture"); - if (!capture_dai_name) - return -ENOMEM; - } /* * CPU == Platform @@ -252,27 +258,23 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[i].num_cpus = 1; priv->dai[i].num_codecs = 1; priv->dai[i].num_platforms = 1; - - priv->dai[i].name = dai_name; + priv->dai[i].name = name[0][i]; priv->dai[i].stream_name = "HiFi-AUDMIX-FE"; priv->dai[i].cpus->of_node = args.np; - priv->dai[i].cpus->dai_name = dev_name(&cpu_pdev->dev); + priv->dai[i].cpus->dai_name = name[1][i]; +
[PATCH 1/3] ASoC: fsl_sai: Add separate DAI for transmitter and receiver
The transmitter and receiver part of the SAI interface need to be configured with different master/slave mode, especially to work with the audiomix module. +---+ +---+ | SAI1 | --TX--> | | | | <--RX-- | | +---+ | | | AUDIOMIX | +---+ | | | SAI2 | --TX--> | | +---+ +---+ The SAI1 TX is in master mode, but SAI1 RX is in slave mode. So add another two DAIs for TX and RX separately. but only defined fsl_sai_set_dai_fmt_tx() and fsl_sai_set_dai_fmt_rx() ops function for current case, in the future, the other ops function for TX and RX can be defined if required. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_sai.c | 141 +--- sound/soc/fsl/fsl_sai.h | 4 +- 2 files changed, 104 insertions(+), 41 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0e2c31439670..d03b0172b8ad 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_BP_FP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_consumer_mode = false; + sai->is_consumer_mode[tx] = false; break; case SND_SOC_DAIFMT_BC_FC: - sai->is_consumer_mode = true; + sai->is_consumer_mode[tx] = true; break; case SND_SOC_DAIFMT_BP_FC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; - sai->is_consumer_mode = false; + sai->is_consumer_mode[tx] = false; break; case SND_SOC_DAIFMT_BC_FP: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; - sai->is_consumer_mode = true; + sai->is_consumer_mode[tx] = true; break; default: return -EINVAL; @@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) return ret; } +static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true); +} + +static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false); +} + static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); @@ -412,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) bool support_1_1_ratio = sai->verid.version >= 0x0301; /* Don't apply to consumer mode */ - if (sai->is_consumer_mode) + if (sai->is_consumer_mode[tx]) return 0; /* @@ -575,7 +585,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - if (!sai->is_consumer_mode) { + if (!sai->is_consumer_mode[tx]) { ret = fsl_sai_set_bclk(cpu_dai, tx, bclk); if (ret) return ret; @@ -613,7 +623,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, * RCR5(TCR5) for playback(capture), or there will be sync error. */ - if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) { + if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) { regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, @@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, * FSD_MSTR bit for this specific case. */ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && - !sai->is_consumer_mode) + !sai->is_consumer_mode[tx]) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FSD_MSTR, 0); @@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, /* Enable FSD_MSTR after configuring word width */ if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && - !sai->is_consumer_mode) + !sai->is_consumer_mode[tx]) regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR); @@ -720,8 +730,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
[PATCH 2/3] ASoC: fsl_audmix: Split playback and capture stream to different DAI
As audmix requires playback and capture stream in different master/slave mode, so separate playback and capture stream to different DAI. There are three DAIs required, two DAIs for playback one DAI for capture. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_audmix.c | 16 ++-- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 0ab2c1962117..1671a3037c60 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -326,15 +326,6 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = FSL_AUDMIX_FORMATS, }, - .capture = { - .stream_name = "AUDMIX-Capture-0", - .channels_min = 8, - .channels_max = 8, - .rate_min = 8000, - .rate_max = 96000, - .rates = SNDRV_PCM_RATE_8000_96000, - .formats = FSL_AUDMIX_FORMATS, - }, .ops = &fsl_audmix_dai_ops, }, { @@ -349,8 +340,13 @@ static struct snd_soc_dai_driver fsl_audmix_dai[] = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = FSL_AUDMIX_FORMATS, }, + .ops = &fsl_audmix_dai_ops, + }, + { + .id = 2, + .name = "audmix-2", .capture = { - .stream_name = "AUDMIX-Capture-1", + .stream_name = "AUDMIX-Capture-0", .channels_min = 8, .channels_max = 8, .rate_min = 8000, -- 2.34.1
[PATCH 0/3] ASoC: imx-audmix: Split capture device to be a new device
The transmitter and receiver part of the SAI interface need to be configured with different master/slave mode, especially to work with the audiomix module. The SAI1 TX is in master mode, but SAI1 RX is in slave mode. So add another two DAIs for TX and RX separately in fsl_sai driver. There will be three devices for audiomix sound card, hw:x,0 is the playback device for one SAI, hw:x,1 is the playback device for another SAI, hw:x,2 is the capture device for audmix output. Shengjiu Wang (3): ASoC: fsl_sai: Add separate DAI for transmitter and receiver ASoC: fsl_audmix: Split playback and capture stream to different DAI ASoC: imx-audmix: Split capture device for audmix sound/soc/fsl/fsl_audmix.c | 16 ++--- sound/soc/fsl/fsl_sai.c| 141 +++-- sound/soc/fsl/fsl_sai.h| 4 +- sound/soc/fsl/imx-audmix.c | 79 - 4 files changed, 155 insertions(+), 85 deletions(-) -- 2.34.1
[PATCH v4 1/2] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. The difference between each platform is in below table. +-++--++ | SOC| PHY | eARC/ARC | SPDIF | +-++--++ | i.MX8MP | V1| Yes | Yes | +-++--++ | i.MX93 | N/A | N/A | Yes | +-++--++ | i.MX95 | V2| N/A | Yes | +-++--++ On i.MX95, there are two PLL clock sources, they are the parent clocks of the XCVR root clock. one is for 8kHz series rates, named as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. They are optional clocks, if there are such clocks, then the driver can switch between them to support more accurate sample rates. As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for clocks and clock-names properties. On i.MX95, the 'interrupts' configuration has the same constraint as i.MX93. Only on i.MX8MP, the 'resets' is required, but for i.MX95 and i.MX93 there is no such hardware setting. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,xcvr.yaml | 32 ++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 0eb0c1ba8710..197ae8ba9c30 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -22,6 +22,7 @@ properties: enum: - fsl,imx8mp-xcvr - fsl,imx93-xcvr + - fsl,imx95-xcvr reg: items: @@ -49,6 +50,9 @@ properties: - description: PHY clock - description: SPBA clock - description: PLL clock + - description: PLL clock source for 8kHz series + - description: PLL clock source for 11kHz series +minItems: 4 clock-names: items: @@ -56,6 +60,9 @@ properties: - const: phy - const: spba - const: pll_ipg + - const: pll8k + - const: pll11k +minItems: 4 dmas: items: @@ -79,15 +86,24 @@ required: - clock-names - dmas - dma-names - - resets allOf: + - if: + properties: +compatible: + contains: +const: fsl,imx8mp-xcvr +then: + required: +- resets + - if: properties: compatible: contains: enum: - fsl,imx93-xcvr + - fsl,imx95-xcvr then: properties: interrupts: @@ -98,6 +114,20 @@ allOf: interrupts: maxItems: 1 + - if: + properties: +compatible: + contains: +enum: + - fsl,imx8mp-xcvr + - fsl,imx93-xcvr +then: + properties: +clocks: + maxItems: 4 +clock-names: + maxItems: 4 + additionalProperties: false examples: -- 2.34.1
[PATCH v4 2/2] ASoC: fsl_xcvr: Add support for i.MX95 platform
On i.MX95, the XCVR uses a new PLL in the PHY, which is General Purpose (GP) PLL. Add GP PLL configuration support in the driver and add the 'pll_ver' flag to distinguish different PLL on different platforms. The XCVR also use PHY but limited for SPDIF only case Add 'use_phy' flag to distinguish these platforms. When there are 'pll8k' and 'pll11k' clock existing, the clock source of 'phy_clk' can be changed for different sample rate requirement. Signed-off-by: Shengjiu Wang Reviewed-by: Chancel Liu --- sound/soc/fsl/Kconfig| 1 + sound/soc/fsl/fsl_xcvr.c | 128 ++- sound/soc/fsl/fsl_xcvr.h | 91 3 files changed, 177 insertions(+), 43 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 270726c134b3..9a371d4496c2 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Audio Transceiver (XCVR) support for NXP iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c46f64557a7f..6b1715ac67c5 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -15,14 +15,22 @@ #include #include "fsl_xcvr.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_XCVR_CAPDS_SIZE256 +enum fsl_xcvr_pll_verison { + PLL_MX8MP, + PLL_MX95, +}; + struct fsl_xcvr_soc_data { const char *fw_name; bool spdif_only; bool use_edma; + bool use_phy; + enum fsl_xcvr_pll_verison pll_ver; }; struct fsl_xcvr { @@ -33,6 +41,8 @@ struct fsl_xcvr { struct clk *pll_ipg_clk; struct clk *phy_clk; struct clk *spba_clk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct reset_control *reset; u8 streams; u32 mode; @@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) { struct device *dev = &xcvr->pdev->dev; - u32 i, div = 0, log2; + u32 i, div = 0, log2, val; int ret; - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { @@ -288,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) return ret; } - /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, - FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); - - /* PLL: CTRL0: DIV_INTEGER */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); - /* PLL: NUMERATOR: MFN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); - /* PLL: DENOMINATOR: MFD */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); - /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); - udelay(25); - /* PLL: CTRL0: Clear Hold Ring Off */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, - FSL_XCVR_PLL_CTRL0_HROFF, 0); - udelay(100); - if (tx) { /* TX is enabled for SPDIF only */ - /* PLL: POSTDIV: PDIV0 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 0), 0); - /* PLL: CTRL_SET: CLKMUX0_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM0_EN, 0); - } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ - /* PLL: POSTDIV: PDIV1 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 1), 0); - /* PLL: CTRL_SET: CLKMUX1_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM1_EN, 0); - } else { /* SPDIF / ARC RX */ - /* PLL: POSTDIV: PDIV2 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 2), 0); - /* PLL: CTRL_SET: CLKMUX2_EN */ + switch (xcvr->soc_data->pll_ver) { + case PLL_MX8MP: + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SE
[PATCH v4 0/2] ASoC: fsl_xcvr: Support i.MX95 platform
On i.MX95 wakeup domain, there is one instance of Audio XCVR supporting SPDIF mode with a connection to the Audio XCVR physical interface. changes in v4: - refine the constarint for 'clocks' according to Rob's comments changes in v3: - refine the constraint for 'resets', 'clocks', 'interrupts' in document. changes in v2: - Merge patch 1&2, 3&4 from v1 together. - Add more comments in commit message - Add constaint for clocks used on i.mx95 - Add 'select SND_SOC_FSL_UTILS' for compiling issue. Shengjiu Wang (2): ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95 ASoC: fsl_xcvr: Add support for i.MX95 platform .../devicetree/bindings/sound/fsl,xcvr.yaml | 32 - sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/fsl_xcvr.c | 128 -- sound/soc/fsl/fsl_xcvr.h | 91 + 4 files changed, 208 insertions(+), 44 deletions(-) -- 2.34.1
Re: [PATCH v3 1/2] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
On Tue, May 28, 2024 at 11:15 PM Rob Herring wrote: > > On Tue, May 21, 2024 at 06:13:35PM +0800, Shengjiu Wang wrote: > > Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. > > > > The difference between each platform is in below table. > > > > +-++--++ > > | SOC | PHY | eARC/ARC | SPDIF | > > +-++--++ > > | i.MX8MP | V1| Yes | Yes | > > +-++--++ > > | i.MX93 | N/A | N/A | Yes | > > +-++--++ > > | i.MX95 | V2| N/A | Yes | > > +-++--++ > > > > On i.MX95, there are two PLL clock sources, they are the parent > > clocks of the XCVR root clock. one is for 8kHz series rates, named > > as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. > > They are optional clocks, if there are such clocks, then the driver > > can switch between them to support more accurate sample rates. > > > > As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for > > clocks and clock-names properties. > > > > On i.MX95, the 'interrupts' configuration has the same constraint > > as i.MX93. > > > > Only on i.MX8MP, the 'resets' is required, but for i.MX95 and i.MX93 > > there is no such hardware setting. > > > > Signed-off-by: Shengjiu Wang > > --- > > .../devicetree/bindings/sound/fsl,xcvr.yaml | 37 ++- > > 1 file changed, 36 insertions(+), 1 deletion(-) > > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > index 0eb0c1ba8710..d1dcc27655eb 100644 > > --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > @@ -22,6 +22,7 @@ properties: > > enum: > >- fsl,imx8mp-xcvr > >- fsl,imx93-xcvr > > + - fsl,imx95-xcvr > > > >reg: > > items: > > @@ -49,6 +50,9 @@ properties: > >- description: PHY clock > >- description: SPBA clock > >- description: PLL clock > > + - description: PLL clock source for 8kHz series > > + - description: PLL clock source for 11kHz series > > +minItems: 4 > > > >clock-names: > > items: > > @@ -56,6 +60,9 @@ properties: > >- const: phy > >- const: spba > >- const: pll_ipg > > + - const: pll8k > > + - const: pll11k > > +minItems: 4 > > > >dmas: > > items: > > @@ -79,15 +86,24 @@ required: > >- clock-names > >- dmas > >- dma-names > > - - resets > > > > allOf: > > + - if: > > + properties: > > +compatible: > > + contains: > > +const: fsl,imx8mp-xcvr > > +then: > > + required: > > +- resets > > + > >- if: > >properties: > > compatible: > >contains: > > enum: > >- fsl,imx93-xcvr > > + - fsl,imx95-xcvr > > then: > >properties: > > interrupts: > > @@ -98,6 +114,25 @@ allOf: > > interrupts: > >maxItems: 1 > > > > + - if: > > + properties: > > +compatible: > > + contains: > > +enum: > > + - fsl,imx95-xcvr > > +then: > > + properties: > > +clocks: > > + maxItems: 6 > > +clock-names: > > + maxItems: 6 > > 6 is already the max. Drop these and add a 'not' into the if schema (or > list out the other compatibles). Ok, will update it. best regards Shengjiu Wang > > > +else: > > + properties: > > +clocks: > > + maxItems: 4 > > +clock-names: > > + maxItems: 4 > > + > > additionalProperties: false > > > > examples: > > -- > > 2.34.1 > >
[PATCH v2 0/2] ASoC: fsl_mqs: Add i.MX95 platform support
There are two MQS instances on the i.MX95 platform. The definition of bit positions in the control register are different. In order to support these MQS modules, define two compatible strings to distinguish them. changes in v2: - remove "fsl,mqs-ctrl" property - use two compatible strings to distinguish two instances Shengjiu Wang (2): ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support ASoC: fsl_mqs: Add i.MX95 platform support .../devicetree/bindings/sound/fsl,mqs.yaml| 2 + sound/soc/fsl/fsl_mqs.c | 46 --- 2 files changed, 42 insertions(+), 6 deletions(-) -- 2.34.1
[PATCH v2 1/2] ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support
There are two MQS instances on the i.MX95 platform. The definition of bit positions in the control register are different. In order to support these MQS modules, define two compatible strings to distinguish them. As one instance is in the always-on domain, another is in the net controller domain, so the compatible strings are "fsl,imx95-aonmix-mqs", "fsl,imx95-netcmix-mqs". Signed-off-by: Shengjiu Wang --- Documentation/devicetree/bindings/sound/fsl,mqs.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml index 8b33353a80ca..030ccc173130 100644 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -23,6 +23,8 @@ properties: - fsl,imx8qm-mqs - fsl,imx8qxp-mqs - fsl,imx93-mqs + - fsl,imx95-aonmix-mqs + - fsl,imx95-netcmix-mqs clocks: minItems: 1 -- 2.34.1
[PATCH v2 2/2] ASoC: fsl_mqs: Add i.MX95 platform support
There are two MQS instances on the i.MX95 platform. The definition of bit positions in the control register are different. In order to support these MQS modules, define two compatible strings to distinguish them. Define different soc data according to compatible strings On i.MX95 one instance in nect-mix is supported by this commit, another instance in always-on-mix is not supported, which depends on System Manager function readiness. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_mqs.c | 46 +++-- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 60929c36a0e3..c95b84a54dc4 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -28,10 +28,16 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +enum reg_type { + TYPE_REG_OWN, /* module own register space */ + TYPE_REG_GPR, /* register in GPR space */ + TYPE_REG_SM, /* System Manager controls the register */ +}; + /** * struct fsl_mqs_soc_data - soc specific data * - * @use_gpr: control register is in General Purpose Register group + * @type: control register space type * @ctrl_off: control register offset * @en_mask: enable bit mask * @en_shift: enable bit shift @@ -43,7 +49,7 @@ * @div_shift: clock divider bit shift */ struct fsl_mqs_soc_data { - bool use_gpr; + enum reg_type type; int ctrl_off; int en_mask; int en_shift; @@ -200,7 +206,7 @@ static int fsl_mqs_probe(struct platform_device *pdev) */ mqs_priv->soc = of_device_get_match_data(&pdev->dev); - if (mqs_priv->soc->use_gpr) { + if (mqs_priv->soc->type == TYPE_REG_GPR) { gpr_np = of_parse_phandle(np, "gpr", 0); if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); @@ -304,7 +310,7 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { - .use_gpr = false, + .type = TYPE_REG_OWN, .ctrl_off = REG_MQS_CTRL, .en_mask = MQS_EN_MASK, .en_shift = MQS_EN_SHIFT, @@ -317,7 +323,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { - .use_gpr = true, + .type = TYPE_REG_GPR, .ctrl_off = IOMUXC_GPR2, .en_mask = IMX6SX_GPR2_MQS_EN_MASK, .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT, @@ -330,7 +336,7 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { }; static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { - .use_gpr = true, + .type = TYPE_REG_GPR, .ctrl_off = 0x20, .en_mask = BIT(1), .en_shift = 1, @@ -342,10 +348,38 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { .div_shift = 8, }; +static const struct fsl_mqs_soc_data fsl_mqs_imx95_aon_data = { + .type = TYPE_REG_SM, + .ctrl_off = 0x88, + .en_mask = BIT(1), + .en_shift = 1, + .rst_mask = BIT(2), + .rst_shift = 2, + .osr_mask = BIT(3), + .osr_shift = 3, + .div_mask = GENMASK(15, 8), + .div_shift = 8, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = { + .type = TYPE_REG_GPR, + .ctrl_off = 0x0, + .en_mask = BIT(2), + .en_shift = 2, + .rst_mask = BIT(3), + .rst_shift = 3, + .osr_mask = BIT(4), + .osr_shift = 4, + .div_mask = GENMASK(16, 9), + .div_shift = 9, +}; + static const struct of_device_id fsl_mqs_dt_ids[] = { { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data }, { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data }, { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data }, + { .compatible = "fsl,imx95-aonmix-mqs", .data = &fsl_mqs_imx95_aon_data }, + { .compatible = "fsl,imx95-netcmix-mqs", .data = &fsl_mqs_imx95_netc_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); -- 2.34.1
[PATCH v3 0/2] ASoC: fsl_xcvr: Support i.MX95 platform
On i.MX95 wakeup domain, there is one instance of Audio XCVR supporting SPDIF mode with a connection to the Audio XCVR physical interface. changes in v3: - refine the constraint for 'resets', 'clocks', 'interrupts' in document. changes in v2: - Merge patch 1&2, 3&4 from v1 together. - Add more comments in commit message - Add constaint for clocks used on i.mx95 - Add 'select SND_SOC_FSL_UTILS' for compiling issue. Shengjiu Wang (2): ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95 ASoC: fsl_xcvr: Add support for i.MX95 platform .../devicetree/bindings/sound/fsl,xcvr.yaml | 37 - sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/fsl_xcvr.c | 128 -- sound/soc/fsl/fsl_xcvr.h | 91 + 4 files changed, 213 insertions(+), 44 deletions(-) -- 2.34.1
[PATCH v3 2/2] ASoC: fsl_xcvr: Add support for i.MX95 platform
On i.MX95, the XCVR uses a new PLL in the PHY, which is General Purpose (GP) PLL. Add GP PLL configuration support in the driver and add the 'pll_ver' flag to distinguish different PLL on different platforms. The XCVR also use PHY but limited for SPDIF only case Add 'use_phy' flag to distinguish these platforms. When there are 'pll8k' and 'pll11k' clock existing, the clock source of 'phy_clk' can be changed for different sample rate requirement. Signed-off-by: Shengjiu Wang Reviewed-by: Chancel Liu --- sound/soc/fsl/Kconfig| 1 + sound/soc/fsl/fsl_xcvr.c | 128 ++- sound/soc/fsl/fsl_xcvr.h | 91 3 files changed, 177 insertions(+), 43 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 270726c134b3..9a371d4496c2 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Audio Transceiver (XCVR) support for NXP iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c46f64557a7f..6b1715ac67c5 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -15,14 +15,22 @@ #include #include "fsl_xcvr.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_XCVR_CAPDS_SIZE256 +enum fsl_xcvr_pll_verison { + PLL_MX8MP, + PLL_MX95, +}; + struct fsl_xcvr_soc_data { const char *fw_name; bool spdif_only; bool use_edma; + bool use_phy; + enum fsl_xcvr_pll_verison pll_ver; }; struct fsl_xcvr { @@ -33,6 +41,8 @@ struct fsl_xcvr { struct clk *pll_ipg_clk; struct clk *phy_clk; struct clk *spba_clk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct reset_control *reset; u8 streams; u32 mode; @@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) { struct device *dev = &xcvr->pdev->dev; - u32 i, div = 0, log2; + u32 i, div = 0, log2, val; int ret; - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { @@ -288,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) return ret; } - /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, - FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); - - /* PLL: CTRL0: DIV_INTEGER */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); - /* PLL: NUMERATOR: MFN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); - /* PLL: DENOMINATOR: MFD */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); - /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); - udelay(25); - /* PLL: CTRL0: Clear Hold Ring Off */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, - FSL_XCVR_PLL_CTRL0_HROFF, 0); - udelay(100); - if (tx) { /* TX is enabled for SPDIF only */ - /* PLL: POSTDIV: PDIV0 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 0), 0); - /* PLL: CTRL_SET: CLKMUX0_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM0_EN, 0); - } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ - /* PLL: POSTDIV: PDIV1 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 1), 0); - /* PLL: CTRL_SET: CLKMUX1_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM1_EN, 0); - } else { /* SPDIF / ARC RX */ - /* PLL: POSTDIV: PDIV2 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 2), 0); - /* PLL: CTRL_SET: CLKMUX2_EN */ + switch (xcvr->soc_data->pll_ver) { + case PLL_MX8MP: + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SE
[PATCH v3 1/2] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. The difference between each platform is in below table. +-++--++ | SOC| PHY | eARC/ARC | SPDIF | +-++--++ | i.MX8MP | V1| Yes | Yes | +-++--++ | i.MX93 | N/A | N/A | Yes | +-++--++ | i.MX95 | V2| N/A | Yes | +-++--++ On i.MX95, there are two PLL clock sources, they are the parent clocks of the XCVR root clock. one is for 8kHz series rates, named as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. They are optional clocks, if there are such clocks, then the driver can switch between them to support more accurate sample rates. As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for clocks and clock-names properties. On i.MX95, the 'interrupts' configuration has the same constraint as i.MX93. Only on i.MX8MP, the 'resets' is required, but for i.MX95 and i.MX93 there is no such hardware setting. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,xcvr.yaml | 37 ++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 0eb0c1ba8710..d1dcc27655eb 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -22,6 +22,7 @@ properties: enum: - fsl,imx8mp-xcvr - fsl,imx93-xcvr + - fsl,imx95-xcvr reg: items: @@ -49,6 +50,9 @@ properties: - description: PHY clock - description: SPBA clock - description: PLL clock + - description: PLL clock source for 8kHz series + - description: PLL clock source for 11kHz series +minItems: 4 clock-names: items: @@ -56,6 +60,9 @@ properties: - const: phy - const: spba - const: pll_ipg + - const: pll8k + - const: pll11k +minItems: 4 dmas: items: @@ -79,15 +86,24 @@ required: - clock-names - dmas - dma-names - - resets allOf: + - if: + properties: +compatible: + contains: +const: fsl,imx8mp-xcvr +then: + required: +- resets + - if: properties: compatible: contains: enum: - fsl,imx93-xcvr + - fsl,imx95-xcvr then: properties: interrupts: @@ -98,6 +114,25 @@ allOf: interrupts: maxItems: 1 + - if: + properties: +compatible: + contains: +enum: + - fsl,imx95-xcvr +then: + properties: +clocks: + maxItems: 6 +clock-names: + maxItems: 6 +else: + properties: +clocks: + maxItems: 4 +clock-names: + maxItems: 4 + additionalProperties: false examples: -- 2.34.1
Re: [PATCH 1/2] ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support
On Mon, May 20, 2024 at 6:47 PM Krzysztof Kozlowski wrote: > > On 17/05/2024 11:45, Shengjiu Wang wrote: > > In order to support the MQS module on i.MX95, a new property > > "fsl,mqs-ctrl" needs to be added, as there are two MQS instances > > on the i.MX95 platform, the definition of bit positions in the > > control register is different. This new property is to distinguish > > these two instances. > > > > Without this property, the difference of platforms except the > > i.MX95 was handled by the driver itself. But this new property can > > also be used for previous platforms. > > > > The MQS only has one control register, the register may be > > in General Purpose Register memory space, or MQS its own > > memory space, or controlled by System Manager. > > The bit position in the register may be different for each > > platform, there are four parts (bits for module enablement, > > bits for reset, bits for oversampling ratio, bits for divider ratio). > > This new property includes all these things. > > ... > > > > >clocks: > > minItems: 1 > > @@ -45,6 +46,22 @@ properties: > >resets: > > maxItems: 1 > > > > + fsl,mqs-ctrl: > > +$ref: /schemas/types.yaml#/definitions/uint32-array > > +minItems: 6 > > +maxItems: 6 > > +description: | > > + Contains the control register information, defined as, > > + Cell #1: register type > > + 0 - the register in owned register map > > + 1 - the register in general purpose register map > > + 2 - the register in control of system manager > > + Cell #2: offset of the control register from the syscon > > + Cell #3: shift bits for module enable bit > > + Cell #4: shift bits for reset bit > > + Cell #5: shift bits for oversampling ratio bit > > + Cell #6: shift bits for divider ratio control bit > > Thanks for detailed explanation in commit msg, but no, please do not > describe layout of registers in DTS. For the syscon phandles, you can > pass an argument (although not 6 arguments...). Usually this is enough. > For some cases, like you have differences in capabilities of this device > or its programming model, maybe you need different compatible. > > If these are different capabilities, sometimes new properties are > applicable (describing hardware, not register bits...). > The main difference between the two instances on i.MX95 is the register difference. looks like I need to use two compatible strings: - fsl,imx95-aonmix-mqs - fsl,imx95-netcmix-mqs to distinguish them. best regards Shengjiu Wang > Best regards, > Krzysztof >
Re: [PATCH v2 1/2] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
On Tue, May 21, 2024 at 12:16 AM Rob Herring wrote: > > On Tue, May 14, 2024 at 11:12:08AM +0800, Shengjiu Wang wrote: > > Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. > > > > The difference between each platform is in below table. > > > > +-++--++ > > | SOC | PHY | eARC/ARC | SPDIF | > > +-++--++ > > | i.MX8MP | V1| Yes | Yes | > > +-++--++ > > | i.MX93 | N/A | N/A | Yes | > > +-++--++ > > | i.MX95 | V2| N/A | Yes | > > +-++--++ > > > > On i.MX95, there are two PLL clock sources, they are the parent > > clocks of the XCVR root clock. one is for 8kHz series rates, named > > as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. > > They are optional clocks, if there are such clocks, then the driver > > can switch between them to support more accurate sample rates. > > > > As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' > > for clocks and clock-names properties. > > > > Signed-off-by: Shengjiu Wang > > --- > > .../devicetree/bindings/sound/fsl,xcvr.yaml | 55 +++ > > 1 file changed, 45 insertions(+), 10 deletions(-) > > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > index 0eb0c1ba8710..70bcde33e986 100644 > > --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > @@ -22,6 +22,7 @@ properties: > > enum: > >- fsl,imx8mp-xcvr > >- fsl,imx93-xcvr > > + - fsl,imx95-xcvr > > > >reg: > > items: > > @@ -44,18 +45,12 @@ properties: > > minItems: 1 > > > >clocks: > > -items: > > - - description: Peripheral clock > > - - description: PHY clock > > - - description: SPBA clock > > - - description: PLL clock > > Leave these here and add pll8k and pll11k. > > > +minItems: 4 > > Keep this. > > > +maxItems: 6 > > > >clock-names: > > -items: > > - - const: ipg > > - - const: phy > > - - const: spba > > - - const: pll_ipg > > +minItems: 4 > > +maxItems: 6 > > Same here. > > > > >dmas: > > items: > > @@ -97,6 +92,46 @@ allOf: > >properties: > > interrupts: > >maxItems: 1 > > + - if: > > + properties: > > +compatible: > > + contains: > > +enum: > > + - fsl,imx95-xcvr > > +then: > > + properties: > > +clocks: > > + items: > > +- description: Peripheral clock > > +- description: PHY clock > > +- description: SPBA clock > > +- description: PLL clock > > +- description: PLL clock source for 8kHz series > > +- description: PLL clock source for 11kHz series > > + minItems: 4 > > +clock-names: > > + items: > > +- const: ipg > > +- const: phy > > +- const: spba > > +- const: pll_ipg > > +- const: pll8k > > +- const: pll11k > > + minItems: 4 > > Drop all this. > > > +else: > > + properties: > > +clocks: > > + items: > > +- description: Peripheral clock > > +- description: PHY clock > > +- description: SPBA clock > > +- description: PLL clock > > +clock-names: > > + items: > > +- const: ipg > > +- const: phy > > +- const: spba > > +- const: pll_ipg > > And for this case, you just need 'maxItems: 4'. > Thanks for the comments. I will address them in the next version. Best regards Shengjiu Wang
[PATCH 2/2] ASoC: fsl_mqs: Add i.MX95 platform support
On i.MX95 there are two MQS instances, so "fsl,mqs-ctrl" need to be used to distinguish them. Only can list the settings of one instance in soc data. As "fsl,mqs-ctrl" is optional, if this property does not exist, the driver will use soc data to configure the MQS module. On i.MX95 one instance in wakeup-mix is supported by this commit, another instance in always-on-mix is not supported, which depends on System Manager function readiness, but it can also benefit from the new property. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_mqs.c | 106 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 60929c36a0e3..3d69ac5736c8 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -28,10 +28,16 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +enum reg_type { + TYPE_REG_OWN, /* module own register space */ + TYPE_REG_GPR, /* register in GPR space */ + TYPE_REG_SM, /* System Manager controls the register */ +}; + /** * struct fsl_mqs_soc_data - soc specific data * - * @use_gpr: control register is in General Purpose Register group + * @type: control register space type * @ctrl_off: control register offset * @en_mask: enable bit mask * @en_shift: enable bit shift @@ -43,7 +49,7 @@ * @div_shift: clock divider bit shift */ struct fsl_mqs_soc_data { - bool use_gpr; + enum reg_type type; int ctrl_off; int en_mask; int en_shift; @@ -60,7 +66,7 @@ struct fsl_mqs { struct regmap *regmap; struct clk *mclk; struct clk *ipg; - const struct fsl_mqs_soc_data *soc; + struct fsl_mqs_soc_data soc; unsigned int reg_mqs_ctrl; }; @@ -90,11 +96,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, res = mclk_rate % (32 * lrclk * 2 * 8); if (res == 0 && div > 0 && div <= 256) { - regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, - mqs_priv->soc->div_mask, - (div - 1) << mqs_priv->soc->div_shift); - regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, - mqs_priv->soc->osr_mask, 0); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc.ctrl_off, + mqs_priv->soc.div_mask, + (div - 1) << mqs_priv->soc.div_shift); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc.ctrl_off, + mqs_priv->soc.osr_mask, 0); } else { dev_err(component->dev, "can't get proper divider\n"); } @@ -135,9 +141,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, - mqs_priv->soc->en_mask, - 1 << mqs_priv->soc->en_shift); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc.ctrl_off, + mqs_priv->soc.en_mask, + 1 << mqs_priv->soc.en_shift); return 0; } @@ -147,8 +153,8 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, - mqs_priv->soc->en_mask, 0); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc.ctrl_off, + mqs_priv->soc.en_mask, 0); } static const struct snd_soc_component_driver soc_codec_fsl_mqs = { @@ -182,9 +188,50 @@ static const struct regmap_config fsl_mqs_regmap_config = { .cache_type = REGCACHE_NONE, }; +static int fsl_mqs_set_soc_data_from_of(struct device_node *np, + struct fsl_mqs_soc_data *soc) +{ + char *propname = "fsl,mqs-ctrl"; + int elems, index; + int ret; + + elems = of_property_count_u32_elems(np, propname); + if (elems == 6) { + index = 0; + + ret = of_property_read_u32_index(np, propname, index++, &soc->type); + if (ret) + return -EINVAL; + + ret = of_property_read_u32_index(np, propname, index++, &soc->ctrl_off); + if (ret) + return -EINVAL; +
[PATCH 0/2] ASoC: fsl_mqs: Add i.MX95 platform support
In order to support the MQS module on i.MX95, a new property "fsl,mqs-ctrl" needs to be added, as there are two MQS instances on the i.MX95 platform, the definition of bit positions in the control register is different. This new property is to distinguish these two instances. Without this property, the difference of platforms except the i.MX95 was handled by the driver itself. But this new property can also be used for previous platforms. The MQS only has one control register, the register may be in General Purpose Register memory space, or MQS its own memory space, or controlled by System Manager. The bit position in the register may be different for each platform, there are four parts (bits for module enablement, bits for reset, bits for oversampling ratio, bits for divider ratio). This new property includes all these things. Shengjiu Wang (2): ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support ASoC: fsl_mqs: Add i.MX95 platform support .../devicetree/bindings/sound/fsl,mqs.yaml| 17 +++ sound/soc/fsl/fsl_mqs.c | 106 ++ 2 files changed, 103 insertions(+), 20 deletions(-) -- 2.34.1
[PATCH 1/2] ASoC: dt-bindings: fsl,mqs: Add i.MX95 platform support
In order to support the MQS module on i.MX95, a new property "fsl,mqs-ctrl" needs to be added, as there are two MQS instances on the i.MX95 platform, the definition of bit positions in the control register is different. This new property is to distinguish these two instances. Without this property, the difference of platforms except the i.MX95 was handled by the driver itself. But this new property can also be used for previous platforms. The MQS only has one control register, the register may be in General Purpose Register memory space, or MQS its own memory space, or controlled by System Manager. The bit position in the register may be different for each platform, there are four parts (bits for module enablement, bits for reset, bits for oversampling ratio, bits for divider ratio). This new property includes all these things. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,mqs.yaml | 17 + 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml index 8b33353a80ca..a2129b7cb147 100644 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -23,6 +23,7 @@ properties: - fsl,imx8qm-mqs - fsl,imx8qxp-mqs - fsl,imx93-mqs + - fsl,imx95-mqs clocks: minItems: 1 @@ -45,6 +46,22 @@ properties: resets: maxItems: 1 + fsl,mqs-ctrl: +$ref: /schemas/types.yaml#/definitions/uint32-array +minItems: 6 +maxItems: 6 +description: | + Contains the control register information, defined as, + Cell #1: register type + 0 - the register in owned register map + 1 - the register in general purpose register map + 2 - the register in control of system manager + Cell #2: offset of the control register from the syscon + Cell #3: shift bits for module enable bit + Cell #4: shift bits for reset bit + Cell #5: shift bits for oversampling ratio bit + Cell #6: shift bits for divider ratio control bit + required: - compatible - clocks -- 2.34.1
Re: [PATCH v15 00/16] Add audio support in v4l2 framework
On Wed, May 15, 2024 at 6:46 PM Jaroslav Kysela wrote: > > On 15. 05. 24 12:19, Takashi Iwai wrote: > > On Wed, 15 May 2024 11:50:52 +0200, > > Jaroslav Kysela wrote: > >> > >> On 15. 05. 24 11:17, Hans Verkuil wrote: > >>> Hi Jaroslav, > >>> > >>> On 5/13/24 13:56, Jaroslav Kysela wrote: > >>>> On 09. 05. 24 13:13, Jaroslav Kysela wrote: > >>>>> On 09. 05. 24 12:44, Shengjiu Wang wrote: > >>>>>>>> mem2mem is just like the decoder in the compress pipeline. which is > >>>>>>>> one of the components in the pipeline. > >>>>>>> > >>>>>>> I was thinking of loopback with endpoints using compress streams, > >>>>>>> without physical endpoint, something like: > >>>>>>> > >>>>>>> compress playback (to feed data from userspace) -> DSP (processing) -> > >>>>>>> compress capture (send data back to userspace) > >>>>>>> > >>>>>>> Unless I'm missing something, you should be able to process data as > >>>>>>> fast > >>>>>>> as you can feed it and consume it in such case. > >>>>>>> > >>>>>> > >>>>>> Actually in the beginning I tried this, but it did not work well. > >>>>>> ALSA needs time control for playback and capture, playback and capture > >>>>>> needs to synchronize. Usually the playback and capture pipeline is > >>>>>> independent in ALSA design, but in this case, the playback and capture > >>>>>> should synchronize, they are not independent. > >>>>> > >>>>> The core compress API core no strict timing constraints. You can > >>>>> eventually0 > >>>>> have two half-duplex compress devices, if you like to have really > >>>>> independent > >>>>> mechanism. If something is missing in API, you can extend this API > >>>>> (like to > >>>>> inform the user space that it's a producer/consumer processing without > >>>>> any > >>>>> relation to the real time). I like this idea. > >>>> > >>>> I was thinking more about this. If I am right, the mentioned use in > >>>> gstreamer > >>>> is supposed to run the conversion (DSP) job in "one shot" (can be handled > >>>> using one system call like blocking ioctl). The goal is just to offload > >>>> the > >>>> CPU work to the DSP (co-processor). If there are no requirements for the > >>>> queuing, we can implement this ioctl in the compress ALSA API easily > >>>> using the > >>>> data management through the dma-buf API. We can eventually define a new > >>>> direction (enum snd_compr_direction) like SND_COMPRESS_CONVERT or so to > >>>> allow > >>>> handle this new data scheme. The API may be extended later on real > >>>> demand, of > >>>> course. > >>>> > >>>> Otherwise all pieces are already in the current ALSA compress API > >>>> (capabilities, params, enumeration). The realtime controls may be created > >>>> using ALSA control API. > >>> > >>> So does this mean that Shengjiu should attempt to use this ALSA approach > >>> first? > >> > >> I've not seen any argument to use v4l2 mem2mem buffer scheme for this > >> data conversion forcefully. It looks like a simple job and ALSA APIs > >> may be extended for this simple purpose. > >> > >> Shengjiu, what are your requirements for gstreamer support? Would be a > >> new blocking ioctl enough for the initial support in the compress ALSA > >> API? > > > > If it works with compress API, it'd be great, yeah. > > So, your idea is to open compress-offload devices for read and write, > > then and let them convert a la batch jobs without timing control? > > > > For full-duplex usages, we might need some more extensions, so that > > both read and write parameters can be synchronized. (So far the > > compress stream is a unidirectional, and the runtime buffer for a > > single stream.) > > > > And the buffer management is based on the fixed size fragments. I > > hope this doesn't matter much for the intended operation? > &
[PATCH v2 2/2] ASoC: fsl_xcvr: Add support for i.MX95 platform
On i.MX95, the XCVR uses a new PLL in the PHY, which is General Purpose (GP) PLL. Add GP PLL configuration support in the driver and add the 'pll_ver' flag to distinguish different PLL on different platforms. The XCVR also use PHY but limited for SPDIF only case Add 'use_phy' flag to distinguish these platforms. When there are 'pll8k' and 'pll11k' clock existing, the clock source of 'phy_clk' can be changed for different sample rate requirement. Signed-off-by: Shengjiu Wang Reviewed-by: Chancel Liu --- sound/soc/fsl/Kconfig| 1 + sound/soc/fsl/fsl_xcvr.c | 128 ++- sound/soc/fsl/fsl_xcvr.h | 91 3 files changed, 177 insertions(+), 43 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 270726c134b3..9a371d4496c2 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -103,6 +103,7 @@ config SND_SOC_FSL_XCVR select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Audio Transceiver (XCVR) support for NXP iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c46f64557a7f..6b1715ac67c5 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -15,14 +15,22 @@ #include #include "fsl_xcvr.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_XCVR_CAPDS_SIZE256 +enum fsl_xcvr_pll_verison { + PLL_MX8MP, + PLL_MX95, +}; + struct fsl_xcvr_soc_data { const char *fw_name; bool spdif_only; bool use_edma; + bool use_phy; + enum fsl_xcvr_pll_verison pll_ver; }; struct fsl_xcvr { @@ -33,6 +41,8 @@ struct fsl_xcvr { struct clk *pll_ipg_clk; struct clk *phy_clk; struct clk *spba_clk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct reset_control *reset; u8 streams; u32 mode; @@ -262,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) { struct device *dev = &xcvr->pdev->dev; - u32 i, div = 0, log2; + u32 i, div = 0, log2, val; int ret; - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { @@ -288,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) return ret; } - /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, - FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); - - /* PLL: CTRL0: DIV_INTEGER */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); - /* PLL: NUMERATOR: MFN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); - /* PLL: DENOMINATOR: MFD */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); - /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); - udelay(25); - /* PLL: CTRL0: Clear Hold Ring Off */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, - FSL_XCVR_PLL_CTRL0_HROFF, 0); - udelay(100); - if (tx) { /* TX is enabled for SPDIF only */ - /* PLL: POSTDIV: PDIV0 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 0), 0); - /* PLL: CTRL_SET: CLKMUX0_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM0_EN, 0); - } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ - /* PLL: POSTDIV: PDIV1 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 1), 0); - /* PLL: CTRL_SET: CLKMUX1_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM1_EN, 0); - } else { /* SPDIF / ARC RX */ - /* PLL: POSTDIV: PDIV2 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 2), 0); - /* PLL: CTRL_SET: CLKMUX2_EN */ + switch (xcvr->soc_data->pll_ver) { + case PLL_MX8MP: + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SE
[PATCH v2 1/2] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. The difference between each platform is in below table. +-++--++ | SOC| PHY | eARC/ARC | SPDIF | +-++--++ | i.MX8MP | V1| Yes | Yes | +-++--++ | i.MX93 | N/A | N/A | Yes | +-++--++ | i.MX95 | V2| N/A | Yes | +-++--++ On i.MX95, there are two PLL clock sources, they are the parent clocks of the XCVR root clock. one is for 8kHz series rates, named as 'pll8k', another one is for 11kHz series rates, named as 'pll11k'. They are optional clocks, if there are such clocks, then the driver can switch between them to support more accurate sample rates. As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for clocks and clock-names properties. Signed-off-by: Shengjiu Wang --- .../devicetree/bindings/sound/fsl,xcvr.yaml | 55 +++ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 0eb0c1ba8710..70bcde33e986 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -22,6 +22,7 @@ properties: enum: - fsl,imx8mp-xcvr - fsl,imx93-xcvr + - fsl,imx95-xcvr reg: items: @@ -44,18 +45,12 @@ properties: minItems: 1 clocks: -items: - - description: Peripheral clock - - description: PHY clock - - description: SPBA clock - - description: PLL clock +minItems: 4 +maxItems: 6 clock-names: -items: - - const: ipg - - const: phy - - const: spba - - const: pll_ipg +minItems: 4 +maxItems: 6 dmas: items: @@ -97,6 +92,46 @@ allOf: properties: interrupts: maxItems: 1 + - if: + properties: +compatible: + contains: +enum: + - fsl,imx95-xcvr +then: + properties: +clocks: + items: +- description: Peripheral clock +- description: PHY clock +- description: SPBA clock +- description: PLL clock +- description: PLL clock source for 8kHz series +- description: PLL clock source for 11kHz series + minItems: 4 +clock-names: + items: +- const: ipg +- const: phy +- const: spba +- const: pll_ipg +- const: pll8k +- const: pll11k + minItems: 4 +else: + properties: +clocks: + items: +- description: Peripheral clock +- description: PHY clock +- description: SPBA clock +- description: PLL clock +clock-names: + items: +- const: ipg +- const: phy +- const: spba +- const: pll_ipg additionalProperties: false -- 2.34.1
[PATCH v2 0/2] ASoC: fsl_xcvr: Support i.MX95 platform
On i.MX95 wakeup domain, there is one instance of Audio XCVR supporting SPDIF mode with a connection to the Audio XCVR physical interface. changes in v2: - Merge patch 1&2, 3&4 from v1 together. - Add more comments in commit message - Add constaint for clocks used on i.mx95 - Add 'select SND_SOC_FSL_UTILS' for compiling issue. Shengjiu Wang (2): ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95 ASoC: fsl_xcvr: Add support for i.MX95 platform .../devicetree/bindings/sound/fsl,xcvr.yaml | 55 ++-- sound/soc/fsl/Kconfig | 1 + sound/soc/fsl/fsl_xcvr.c | 128 -- sound/soc/fsl/fsl_xcvr.h | 91 + 4 files changed, 222 insertions(+), 53 deletions(-) -- 2.34.1
Re: [PATCH 2/4] ASoC: dt-bindings: fsl,xcvr: Add two PLL clock sources
On Fri, May 10, 2024 at 10:27 AM Shengjiu Wang wrote: > > On Fri, May 10, 2024 at 1:14 AM Conor Dooley wrote: > > > > On Thu, May 09, 2024 at 10:57:38AM +0800, Shengjiu Wang wrote: > > > Add two PLL clock sources, they are the parent clocks of the root clock > > > one is for 8kHz series rates, named as 'pll8k', another one is for > > > 11kHz series rates, named as 'pll11k'. They are optional clocks, > > > if there are such clocks, then the driver can switch between them to > > > support more accurate sample rates. > > > > > > As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for > > > clocks and clock-names properties. > > > > Despite the detail given here in the commit message, the series this is > > appearing in and one of the driver patches makes me a bit "suspicious" > > of this patch. Are these newly added clocks available on all devices, or > > just on the imx95, or? > > These newly added clocks are only available for the imx95 XCVR. > Looks like I should merge patch1 & 2 together, patch 3 & 3 together. right? Best regards Shengjiu Wang > Best regards > Shengjiu Wang > > > > Thanks, > > Conor. > > > > > > > > Signed-off-by: Shengjiu Wang > > > --- > > > Documentation/devicetree/bindings/sound/fsl,xcvr.yaml | 6 ++ > > > 1 file changed, 6 insertions(+) > > > > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > > b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > > index 1c74a32def09..c4660faed404 100644 > > > --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > > +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > > @@ -50,6 +50,9 @@ properties: > > >- description: PHY clock > > >- description: SPBA clock > > >- description: PLL clock > > > + - description: PLL clock source for 8kHz series > > > + - description: PLL clock source for 11kHz series > > > +minItems: 4 > > > > > >clock-names: > > > items: > > > @@ -57,6 +60,9 @@ properties: > > >- const: phy > > >- const: spba > > >- const: pll_ipg > > > + - const: pll8k > > > + - const: pll11k > > > +minItems: 4 > > > > > >dmas: > > > items: > > > -- > > > 2.34.1 > > >
Re: [PATCH 1/4] ASoC: dt-bindings: fsl,xcvr: Add compatible string for i.MX95
On Fri, May 10, 2024 at 1:11 AM Conor Dooley wrote: > > On Thu, May 09, 2024 at 10:57:37AM +0800, Shengjiu Wang wrote: > > Add compatible string "fsl,imx95-xcvr" for i.MX95 platform. > > That's apparent from the diff. Why is it not compatible with existing > devices? i.MX8MP: There is PHY and support eARC, ARC, SPDIF i.MX93: There is no PHY and support SPDIF only i.MX95: There is PHY (PHY is different with i.MX8MP), only support SPDIF. Will add such info in the commit message. Best regards Shengjiu > > Cheers, > Conor. > > > > > Signed-off-by: Shengjiu Wang > > --- > > Documentation/devicetree/bindings/sound/fsl,xcvr.yaml | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > index 0eb0c1ba8710..1c74a32def09 100644 > > --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > @@ -22,6 +22,7 @@ properties: > > enum: > >- fsl,imx8mp-xcvr > >- fsl,imx93-xcvr > > + - fsl,imx95-xcvr > > > >reg: > > items: > > -- > > 2.34.1 > >
Re: [PATCH 2/4] ASoC: dt-bindings: fsl,xcvr: Add two PLL clock sources
On Fri, May 10, 2024 at 1:14 AM Conor Dooley wrote: > > On Thu, May 09, 2024 at 10:57:38AM +0800, Shengjiu Wang wrote: > > Add two PLL clock sources, they are the parent clocks of the root clock > > one is for 8kHz series rates, named as 'pll8k', another one is for > > 11kHz series rates, named as 'pll11k'. They are optional clocks, > > if there are such clocks, then the driver can switch between them to > > support more accurate sample rates. > > > > As 'pll8k' and 'pll11k' are optional, then add 'minItems: 4' for > > clocks and clock-names properties. > > Despite the detail given here in the commit message, the series this is > appearing in and one of the driver patches makes me a bit "suspicious" > of this patch. Are these newly added clocks available on all devices, or > just on the imx95, or? These newly added clocks are only available for the imx95 XCVR. Best regards Shengjiu Wang > > Thanks, > Conor. > > > > > Signed-off-by: Shengjiu Wang > > --- > > Documentation/devicetree/bindings/sound/fsl,xcvr.yaml | 6 ++ > > 1 file changed, 6 insertions(+) > > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > index 1c74a32def09..c4660faed404 100644 > > --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml > > @@ -50,6 +50,9 @@ properties: > >- description: PHY clock > >- description: SPBA clock > >- description: PLL clock > > + - description: PLL clock source for 8kHz series > > + - description: PLL clock source for 11kHz series > > +minItems: 4 > > > >clock-names: > > items: > > @@ -57,6 +60,9 @@ properties: > >- const: phy > >- const: spba > >- const: pll_ipg > > + - const: pll8k > > + - const: pll11k > > +minItems: 4 > > > >dmas: > > items: > > -- > > 2.34.1 > >
Re: [PATCH v15 00/16] Add audio support in v4l2 framework
On Thu, May 9, 2024 at 6:28 PM Amadeusz Sławiński wrote: > > On 5/9/2024 12:12 PM, Shengjiu Wang wrote: > > On Thu, May 9, 2024 at 5:50 PM Amadeusz Sławiński > > wrote: > >> > >> On 5/9/2024 11:36 AM, Shengjiu Wang wrote: > >>> On Wed, May 8, 2024 at 4:14 PM Amadeusz Sławiński > >>> wrote: > >>>> > >>>> On 5/8/2024 10:00 AM, Hans Verkuil wrote: > >>>>> On 06/05/2024 10:49, Shengjiu Wang wrote: > >>>>>> On Fri, May 3, 2024 at 4:42 PM Mauro Carvalho Chehab > >>>>>> wrote: > >>>>>>> > >>>>>>> Em Fri, 3 May 2024 10:47:19 +0900 > >>>>>>> Mark Brown escreveu: > >>>>>>> > >>>>>>>> On Thu, May 02, 2024 at 10:26:43AM +0100, Mauro Carvalho Chehab > >>>>>>>> wrote: > >>>>>>>>> Mauro Carvalho Chehab escreveu: > >>>>>>>> > >>>>>>>>>> There are still time control associated with it, as audio and video > >>>>>>>>>> needs to be in sync. This is done by controlling the buffers size > >>>>>>>>>> and could be fine-tuned by checking when the buffer transfer is > >>>>>>>>>> done. > >>>>>>>> > >>>>>>>> ... > >>>>>>>> > >>>>>>>>> Just complementing: on media, we do this per video buffer (or > >>>>>>>>> per half video buffer). A typical use case on cameras is to have > >>>>>>>>> buffers transferred 30 times per second, if the video was streamed > >>>>>>>>> at 30 frames per second. > >>>>>>>> > >>>>>>>> IIRC some big use case for this hardware was transcoding so there > >>>>>>>> was a > >>>>>>>> desire to just go at whatever rate the hardware could support as > >>>>>>>> there > >>>>>>>> is no interactive user consuming the output as it is generated. > >>>>>>> > >>>>>>> Indeed, codecs could be used to just do transcoding, but I would > >>>>>>> expect it to be a border use case. See, as the chipsets implementing > >>>>>>> codecs are typically the ones used on mobiles, I would expect that > >>>>>>> the major use cases to be to watch audio and video and to participate > >>>>>>> on audio/video conferences. > >>>>>>> > >>>>>>> Going further, the codec API may end supporting not only transcoding > >>>>>>> (which is something that CPU can usually handle without too much > >>>>>>> processing) but also audio processing that may require more > >>>>>>> complex algorithms - even deep learning ones - like background noise > >>>>>>> removal, echo detection/removal, volume auto-gain, audio enhancement > >>>>>>> and such. > >>>>>>> > >>>>>>> On other words, the typical use cases will either have input > >>>>>>> or output being a physical hardware (microphone or speaker). > >>>>>>> > >>>>>> > >>>>>> All, thanks for spending time to discuss, it seems we go back to > >>>>>> the start point of this topic again. > >>>>>> > >>>>>> Our main request is that there is a hardware sample rate converter > >>>>>> on the chip, so users can use it in user space as a component like > >>>>>> software sample rate converter. It mostly may run as a gstreamer > >>>>>> plugin. > >>>>>> so it is a memory to memory component. > >>>>>> > >>>>>> I didn't find such API in ALSA for such purpose, the best option for > >>>>>> this > >>>>>> in the kernel is the V4L2 memory to memory framework I found. > >>>>>> As Hans said it is well designed for memory to memory. > >>>>>> > >>>>>> And I think audio is one of 'media'. As I can see that part of Radio > >>>>>> function is in ALSA, part of Radio function is in V4L2. part of HDMI > >>>>>> functio
Re: [PATCH v15 00/16] Add audio support in v4l2 framework
On Thu, May 9, 2024 at 5:50 PM Amadeusz Sławiński wrote: > > On 5/9/2024 11:36 AM, Shengjiu Wang wrote: > > On Wed, May 8, 2024 at 4:14 PM Amadeusz Sławiński > > wrote: > >> > >> On 5/8/2024 10:00 AM, Hans Verkuil wrote: > >>> On 06/05/2024 10:49, Shengjiu Wang wrote: > >>>> On Fri, May 3, 2024 at 4:42 PM Mauro Carvalho Chehab > >>>> wrote: > >>>>> > >>>>> Em Fri, 3 May 2024 10:47:19 +0900 > >>>>> Mark Brown escreveu: > >>>>> > >>>>>> On Thu, May 02, 2024 at 10:26:43AM +0100, Mauro Carvalho Chehab wrote: > >>>>>>> Mauro Carvalho Chehab escreveu: > >>>>>> > >>>>>>>> There are still time control associated with it, as audio and video > >>>>>>>> needs to be in sync. This is done by controlling the buffers size > >>>>>>>> and could be fine-tuned by checking when the buffer transfer is done. > >>>>>> > >>>>>> ... > >>>>>> > >>>>>>> Just complementing: on media, we do this per video buffer (or > >>>>>>> per half video buffer). A typical use case on cameras is to have > >>>>>>> buffers transferred 30 times per second, if the video was streamed > >>>>>>> at 30 frames per second. > >>>>>> > >>>>>> IIRC some big use case for this hardware was transcoding so there was a > >>>>>> desire to just go at whatever rate the hardware could support as there > >>>>>> is no interactive user consuming the output as it is generated. > >>>>> > >>>>> Indeed, codecs could be used to just do transcoding, but I would > >>>>> expect it to be a border use case. See, as the chipsets implementing > >>>>> codecs are typically the ones used on mobiles, I would expect that > >>>>> the major use cases to be to watch audio and video and to participate > >>>>> on audio/video conferences. > >>>>> > >>>>> Going further, the codec API may end supporting not only transcoding > >>>>> (which is something that CPU can usually handle without too much > >>>>> processing) but also audio processing that may require more > >>>>> complex algorithms - even deep learning ones - like background noise > >>>>> removal, echo detection/removal, volume auto-gain, audio enhancement > >>>>> and such. > >>>>> > >>>>> On other words, the typical use cases will either have input > >>>>> or output being a physical hardware (microphone or speaker). > >>>>> > >>>> > >>>> All, thanks for spending time to discuss, it seems we go back to > >>>> the start point of this topic again. > >>>> > >>>> Our main request is that there is a hardware sample rate converter > >>>> on the chip, so users can use it in user space as a component like > >>>> software sample rate converter. It mostly may run as a gstreamer plugin. > >>>> so it is a memory to memory component. > >>>> > >>>> I didn't find such API in ALSA for such purpose, the best option for this > >>>> in the kernel is the V4L2 memory to memory framework I found. > >>>> As Hans said it is well designed for memory to memory. > >>>> > >>>> And I think audio is one of 'media'. As I can see that part of Radio > >>>> function is in ALSA, part of Radio function is in V4L2. part of HDMI > >>>> function is in DRM, part of HDMI function is in ALSA... > >>>> So using V4L2 for audio is not new from this point of view. > >>>> > >>>> Even now I still think V4L2 is the best option, but it looks like there > >>>> are a lot of rejects. If develop a new ALSA-mem2mem, it is also > >>>> a duplication of code (bigger duplication that just add audio support > >>>> in V4L2 I think). > >>> > >>> After reading this thread I still believe that the mem2mem framework is > >>> a reasonable option, unless someone can come up with a method that is > >>> easy to implement in the alsa subsystem. From what I can tell from this > >>> discussion no such method exists. > >>> > >> > >> Hi, > &g
Re: [PATCH v15 00/16] Add audio support in v4l2 framework
On Wed, May 8, 2024 at 4:14 PM Amadeusz Sławiński wrote: > > On 5/8/2024 10:00 AM, Hans Verkuil wrote: > > On 06/05/2024 10:49, Shengjiu Wang wrote: > >> On Fri, May 3, 2024 at 4:42 PM Mauro Carvalho Chehab > >> wrote: > >>> > >>> Em Fri, 3 May 2024 10:47:19 +0900 > >>> Mark Brown escreveu: > >>> > >>>> On Thu, May 02, 2024 at 10:26:43AM +0100, Mauro Carvalho Chehab wrote: > >>>>> Mauro Carvalho Chehab escreveu: > >>>> > >>>>>> There are still time control associated with it, as audio and video > >>>>>> needs to be in sync. This is done by controlling the buffers size > >>>>>> and could be fine-tuned by checking when the buffer transfer is done. > >>>> > >>>> ... > >>>> > >>>>> Just complementing: on media, we do this per video buffer (or > >>>>> per half video buffer). A typical use case on cameras is to have > >>>>> buffers transferred 30 times per second, if the video was streamed > >>>>> at 30 frames per second. > >>>> > >>>> IIRC some big use case for this hardware was transcoding so there was a > >>>> desire to just go at whatever rate the hardware could support as there > >>>> is no interactive user consuming the output as it is generated. > >>> > >>> Indeed, codecs could be used to just do transcoding, but I would > >>> expect it to be a border use case. See, as the chipsets implementing > >>> codecs are typically the ones used on mobiles, I would expect that > >>> the major use cases to be to watch audio and video and to participate > >>> on audio/video conferences. > >>> > >>> Going further, the codec API may end supporting not only transcoding > >>> (which is something that CPU can usually handle without too much > >>> processing) but also audio processing that may require more > >>> complex algorithms - even deep learning ones - like background noise > >>> removal, echo detection/removal, volume auto-gain, audio enhancement > >>> and such. > >>> > >>> On other words, the typical use cases will either have input > >>> or output being a physical hardware (microphone or speaker). > >>> > >> > >> All, thanks for spending time to discuss, it seems we go back to > >> the start point of this topic again. > >> > >> Our main request is that there is a hardware sample rate converter > >> on the chip, so users can use it in user space as a component like > >> software sample rate converter. It mostly may run as a gstreamer plugin. > >> so it is a memory to memory component. > >> > >> I didn't find such API in ALSA for such purpose, the best option for this > >> in the kernel is the V4L2 memory to memory framework I found. > >> As Hans said it is well designed for memory to memory. > >> > >> And I think audio is one of 'media'. As I can see that part of Radio > >> function is in ALSA, part of Radio function is in V4L2. part of HDMI > >> function is in DRM, part of HDMI function is in ALSA... > >> So using V4L2 for audio is not new from this point of view. > >> > >> Even now I still think V4L2 is the best option, but it looks like there > >> are a lot of rejects. If develop a new ALSA-mem2mem, it is also > >> a duplication of code (bigger duplication that just add audio support > >> in V4L2 I think). > > > > After reading this thread I still believe that the mem2mem framework is > > a reasonable option, unless someone can come up with a method that is > > easy to implement in the alsa subsystem. From what I can tell from this > > discussion no such method exists. > > > > Hi, > > my main question would be how is mem2mem use case different from > loopback exposing playback and capture frontends in user space with DSP > (or other piece of HW) in the middle? > I think loopback has a timing control, user need to feed data to playback at a fixed time and get data from capture at a fixed time. Otherwise there is xrun in playback and capture. mem2mem case: there is no such timing control, user feeds data to it then it generates output, if user doesn't feed data, there is no xrun. but mem2mem is just one of the components in the playback or capture pipeline, overall there is time control for whole pipeline, Best regards Shengjiu Wang > Amadeusz >
[PATCH 4/4] ASoC: fsl_xcvr: Add support for i.MX95 platform
On i.MX95, the XCVR uses a new PLL in the PHY, which is General Purpose (GP) PLL. Add GP PLL configuration support in the driver and add the 'pll_ver' flag to distinguish different PLL on different platforms. The XCVR also use PHY but limited for SPDIF only case Add 'use_phy' flag to distinguish these platforms. Signed-off-by: Shengjiu Wang Reviewed-by: Chancel Liu --- sound/soc/fsl/fsl_xcvr.c | 120 +-- sound/soc/fsl/fsl_xcvr.h | 91 + 2 files changed, 168 insertions(+), 43 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 0ffa10e924ef..6b1715ac67c5 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -20,10 +20,17 @@ #define FSL_XCVR_CAPDS_SIZE256 +enum fsl_xcvr_pll_verison { + PLL_MX8MP, + PLL_MX95, +}; + struct fsl_xcvr_soc_data { const char *fw_name; bool spdif_only; bool use_edma; + bool use_phy; + enum fsl_xcvr_pll_verison pll_ver; }; struct fsl_xcvr { @@ -265,10 +272,10 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy) static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) { struct device *dev = &xcvr->pdev->dev; - u32 i, div = 0, log2; + u32 i, div = 0, log2, val; int ret; - if (xcvr->soc_data->spdif_only) + if (!xcvr->soc_data->use_phy) return 0; for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) { @@ -291,45 +298,62 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx) return ret; } - /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, - FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); - - /* PLL: CTRL0: DIV_INTEGER */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); - /* PLL: NUMERATOR: MFN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); - /* PLL: DENOMINATOR: MFD */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); - /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); - udelay(25); - /* PLL: CTRL0: Clear Hold Ring Off */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, - FSL_XCVR_PLL_CTRL0_HROFF, 0); - udelay(100); - if (tx) { /* TX is enabled for SPDIF only */ - /* PLL: POSTDIV: PDIV0 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 0), 0); - /* PLL: CTRL_SET: CLKMUX0_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM0_EN, 0); - } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */ - /* PLL: POSTDIV: PDIV1 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 1), 0); - /* PLL: CTRL_SET: CLKMUX1_EN */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM1_EN, 0); - } else { /* SPDIF / ARC RX */ - /* PLL: POSTDIV: PDIV2 */ - fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV, - FSL_XCVR_PLL_PDIVx(log2, 2), 0); - /* PLL: CTRL_SET: CLKMUX2_EN */ + switch (xcvr->soc_data->pll_ver) { + case PLL_MX8MP: + /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET, + FSL_XCVR_PLL_BANDGAP_EN_VBG, 0); + + /* PLL: CTRL0: DIV_INTEGER */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0); + /* PLL: NUMERATOR: MFN */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0); + /* PLL: DENOMINATOR: MFD */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0); + /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET, - FSL_XCVR_PLL_CTRL0_CM2_EN, 0); + FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0); + udelay(25); + /* PLL: CTRL0: Clear Hold Ring Off */ + fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR, + FSL_XCVR_PLL_CTRL0_HROFF, 0); + udelay(100); + if (tx) { /* TX is enabled for SPDIF only */ + /* PLL: POSTDIV: P
[PATCH 3/4] ASoC: fsl_xcvr: Support reparent pll clocks for phy_clk
When there are 'pll8k' and 'pll11k' clock existing, the clock source of 'phy_clk' can be changed for different sample rate requirement. Signed-off-by: Shengjiu Wang --- sound/soc/fsl/fsl_xcvr.c | 8 1 file changed, 8 insertions(+) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c46f64557a7f..0ffa10e924ef 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -15,6 +15,7 @@ #include #include "fsl_xcvr.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_XCVR_CAPDS_SIZE256 @@ -33,6 +34,8 @@ struct fsl_xcvr { struct clk *pll_ipg_clk; struct clk *phy_clk; struct clk *spba_clk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct reset_control *reset; u8 streams; u32 mode; @@ -362,6 +365,8 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq) freq = xcvr->soc_data->spdif_only ? freq / 5 : freq; clk_disable_unprepare(xcvr->phy_clk); + fsl_asoc_reparent_pll_clocks(dev, xcvr->phy_clk, +xcvr->pll8k_clk, xcvr->pll11k_clk, freq); ret = clk_set_rate(xcvr->phy_clk, freq); if (ret < 0) { dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret); @@ -1287,6 +1292,9 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return PTR_ERR(xcvr->pll_ipg_clk); } + fsl_asoc_get_pll_clocks(dev, &xcvr->pll8k_clk, + &xcvr->pll11k_clk); + xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram"); if (IS_ERR(xcvr->ram_addr)) return PTR_ERR(xcvr->ram_addr); -- 2.34.1