On Wed, Oct 23, 2024 at 9:10 AM Charles Keepax <ckeepax@xxxxxxxxxxxxxxxxxxxxx> wrote: > > On Sun, Oct 20, 2024 at 09:37:06AM -0700, anish kumar wrote: > > Updated documentation to provide more details > > for codec-to-codec connection. > > > > Signed-off-by: anish kumar <yesanishhere@xxxxxxxxx> > > --- > > The patch doesn't seem to apply cleanly for me, my system doesn't > seem to like: > > Content-Type: text/plain; charset="y" > > Not sure if that is a problem on my end or yours, but I am not > familiar with that encoding. > > > v2: Fixed the compilation error reported by Sphinx > > Documentation/sound/soc/codec-to-codec.rst | 296 +++++++++++++-------- > > 1 file changed, 190 insertions(+), 106 deletions(-) > > > > diff --git a/Documentation/sound/soc/codec-to-codec.rst b/Documentation/sound/soc/codec-to-codec.rst > > index 0418521b6e03..9d65fc74856a 100644 > > --- a/Documentation/sound/soc/codec-to-codec.rst > > +++ b/Documentation/sound/soc/codec-to-codec.rst > > @@ -1,115 +1,199 @@ > > -============================================== > > -Creating codec to codec dai link for ALSA dapm > > -============================================== > > +Codec-to-Codec Connections in ALSA > > +==================================== > > > > -Mostly the flow of audio is always from CPU to codec so your system > > -will look as below: > > -:: > > +An ALSA-based audio system typically involves playback and capture > > +functionalities, where users may require audio file playback through > > functionality would probably parse slightly better. > > > +speakers or recording from microphones. However, certain systems > > +necessitate audio data routing directly between components, such as FM > > +radio to speakers, without CPU involvement. For such scenarios, ALSA > > It would probably be more accurate to say "ASoC provides", I mean > I guess ASoC is a part of ALSA but this is definitely an ASoC > level feature. > > > +provides a mechanism known as codec-to-codec connections, leveraging > > +the Dynamic Audio Power Management (DAPM) framework to facilitate > > +direct data transfers between codecs. > > > > - --------- --------- > > - | | dai | | > > - CPU -------> codec > > - | | | | > > - --------- --------- > > +Introduction > > +------------ > > > > -In case your system looks as below: > > -:: > > +In most audio systems, audio data flows from the CPU to the codec. In > > +specific configurations, such as those involving Bluetooth codecs, > > +audio can be transmitted directly between codecs without CPU > > +intervention. ALSA supports both architectures, and for systems that > > +do not involve the CPU, it utilizes codec-to-codec digital audio > > +interface (DAI) connections. This document discusses the procedure > > +for establishing codec-to-codec DAI links to enable such > > +functionalities. > > > > +Audio Data Flow Paths > > +---------------------- > > + > > +In a typical configuration, audio flow can be visualized as follows: > > + > > +.. code-block:: text > > + > > + --------- --------- > > + | | dai | | > > + CPU -------> codec > > + | | | | > > + --------- --------- > > + > > +In more intricate setups, the system may not involve the CPU but > > +instead utilizes multiple codecs as shown below. For instance, > > +Codec-2 acts as a cellular modem, while Codec-3 connects to a > > +speaker. Audio data can be received by Codec-2 and transmitted to > > +Codec-3 without CPU intervention, demonstrating the ideal conditions > > +for establishing a codec-to-codec DAI connection. > > + > > +.. code-block:: text > > + > > + --------- > > + | | > > + codec-1 <---cellular modem > > + | | > > --------- > > - | | > > - codec-2 > > - | | > > - --------- > > - | > > - dai-2 > > - | > > - ---------- --------- > > - | | dai-1 | | > > - CPU -------> codec-1 > > - | | | | > > - ---------- --------- > > - | > > - dai-3 > > - | > > - --------- > > - | | > > - codec-3 > > - | | > > + | > > + dai-1 > > + ↓ > > + ---------- --------- > > + | |cpu_dai | | > > + dummy CPU -------> codec-2 > > Bringing the "dummy" into this is quite misleading, that really > relates to DPCM setups. DPCM lets one select any number of back > ends to service a given front end PCM, and often are abused to > achieve things that should really be implemented as C2C links. Aha, understood. For C2C we need a thin dummy codec driver which acts as a cpu driver in the ASoC code right? Based on the code from bells.c, below is the C2C and we do provide a CPU driver, even though in actual it is a codec driver. SND_SOC_DAILINK_DEFS(wm2200_dsp_codec, DAILINK_COMP_ARRAY(COMP_CPU("wm0010-sdi2")), DAILINK_COMP_ARRAY(COMP_CODEC("wm2200.1-003a", "wm2200"))); Perhaps, I can just remove the "dummy" from the diagram above. > > > + | | | | > > + ---------- --------- > > + | > > + dai-3 > > + ↓ > > + --------- > > + | | > > + codec-3 ---->speaker > > + | | > > --------- > > > > -Suppose codec-2 is a bluetooth chip and codec-3 is connected to > > -a speaker and you have a below scenario: > > -codec-2 will receive the audio data and the user wants to play that > > -audio through codec-3 without involving the CPU.This > > -aforementioned case is the ideal case when codec to codec > > -connection should be used. > > - > > -Your dai_link should appear as below in your machine > > -file: > > -:: > > - > > - /* > > - * this pcm stream only supports 24 bit, 2 channel and > > - * 48k sampling rate. > > - */ > > - static const struct snd_soc_pcm_stream dsp_codec_params = { > > - .formats = SNDRV_PCM_FMTBIT_S24_LE, > > - .rate_min = 48000, > > - .rate_max = 48000, > > - .channels_min = 2, > > - .channels_max = 2, > > - }; > > - > > - { > > - .name = "CPU-DSP", > > - .stream_name = "CPU-DSP", > > - .cpu_dai_name = "samsung-i2s.0", > > - .codec_name = "codec-2, > > - .codec_dai_name = "codec-2-dai_name", > > - .platform_name = "samsung-i2s.0", > > - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > > - | SND_SOC_DAIFMT_CBM_CFM, > > - .ignore_suspend = 1, > > - .c2c_params = &dsp_codec_params, > > - .num_c2c_params = 1, > > - }, > > - { > > - .name = "DSP-CODEC", > > - .stream_name = "DSP-CODEC", > > - .cpu_dai_name = "wm0010-sdi2", > > - .codec_name = "codec-3, > > - .codec_dai_name = "codec-3-dai_name", > > - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > > - | SND_SOC_DAIFMT_CBM_CFM, > > - .ignore_suspend = 1, > > - .c2c_params = &dsp_codec_params, > > - .num_c2c_params = 1, > > - }, > > - > > -Above code snippet is motivated from sound/soc/samsung/speyside.c. > > - > > -Note the "c2c_params" callback which lets the dapm know that this > > -dai_link is a codec to codec connection. > > - > > -In dapm core a route is created between cpu_dai playback widget > > -and codec_dai capture widget for playback path and vice-versa is > > -true for capture path. In order for this aforementioned route to get > > -triggered, DAPM needs to find a valid endpoint which could be either > > -a sink or source widget corresponding to playback and capture path > > +Creating Codec-to-Codec Connections in ALSA > > +---------------------------------------------- > > + > > +To create a codec-to-codec DAI in ALSA, a ``snd_soc_dai_link`` must be > > +added to the machine driver before registering the sound card. > > +During this registration, the core checks for the presence of > > +``c2c_params`` within the ``snd_soc_dai_link``, determining whether > > +to classify the DAI link as codec-to-codec. > > + > > +While establishing the PCM node, the ALSA core inspects this > > +parameter. Instead of generating a user-space PCM node, it creates > > +an internal PCM node utilized by kernel drivers. Consequently, > > I am not sure I like the description of this as an internal PCM > node, I guess in some ways the core does use the same structures > it would for a PCM node, but it isn't really a PCM node. I > do like that you have added the additional note this will not be > visible through procfs though. thanks. > > > +running ``cat /proc/asound/pcm`` will yield no visible PCM nodes. > > + > > +After this setup, the ALSA core invokes the DAPM core to connect a > > Again really ASoC core here. > > > +single ``cpu_dai`` with both ``codec_dais``. Boot-up logs will > > +display messages similar to: > > That is definitely not what should be happening with a C2C link. > In the system you showed the diagram for above there should be a > connection between the CPU and codec-2, then two separate links > between codec-2 and codecs 1 and 3. No links should be present > between the CPU and codecs 1 or 3. Got it, I will try to convey the same in the diagram but ascii art is hard :) Can you help clarify my understanding (based on the dapm code walkthrough), when the mixer control is triggered, the CPU widgets gets triggered thereby triggering codec2 widgets and as there is a static connection between codec1 and codec2 it gets also triggered and the same thing happens to codec3 as it is also linked to codec2? Also, as the widgets are linked to dai ops, all the ops gets triggered as well. > > > + > > +.. code-block:: bash > > + > > + ASoC: registered pcm #0 codec2codec(Playback Codec) > > + multicodec <-> cpu_dai mapping ok > > + connected DAI link Dummy-CPU:cpu_dai -> codec-1:dai_1 > > + connected DAI link Dummy-CPU:cpu_dai -> codec-2:dai_2 > > + > > Yeah this is definitely mixing in a fair amount of DPCM stuff and > does not match the rest of the description. I guess what you meant is that C2C doesn't care about the above connection as it uses DAPM widget connection to trigger the path right? So, even if this connection doesn't exist C2C will still work. Reason why I am asking is that I saw the above logs when I added a C2C connection. > > > +To trigger this DAI link, a control interface is established by the > > +DAPM core during internal DAI creation. This interface links to > > +the ``snd_soc_dai_link_event`` function, which is invoked when a > > +path connects in the DAPM core. A mixer must be created to trigger > > +the connection, prompting the DAPM core to evaluate path > > +connections and call the ``snd_soc_dai_link_event`` callback with > > +relevant events. > > + > > +It is important to note that not all operations defined in > > +``snd_soc_dai_ops`` are invoked as codec-to-codec connections offer > > +limited control over DAI configuration. For greater control, a > > +hostless configuration is recommended. The operations typically > > It is not clear to me what a "hostless configuration" is here. What I meant to convey is, if the user wants all pcm ops to get called in order then he can use "Hostless FE" and connect to backend use as a normal PCM. > > > +executed in codec-to-codec setups include startup, ``hw_params``, > > +``hw_free``, digital mute, and shutdown from the > > +``snd_soc_dai_ops`` structure. > > + > > +Code Changes for Codec-to-Codec > > +---------------------------------- > > + > > +The DAI link configuration in the machine file should resemble the > > +following code snippet: > > + > > +.. code-block:: c > > + > > + /* > > + * This PCM stream only supports 24-bit, 2 channels, and > > + * 48kHz sampling rate. > > + */ > > + static const struct snd_soc_pcm_stream dsp_codec_params = { > > + .formats = SNDRV_PCM_FMTBIT_S24_LE, > > + .rate_min = 48000, > > + .rate_max = 48000, > > + .channels_min = 2, > > + .channels_max = 2, > > + }; > > + > > + static struct snd_soc_dai_link dai_links[] = { > > + { > > + .name = "CPU-DSP", > > + .stream_name = "CPU-DSP", > > + .cpu_dai_name = "samsung-i2s.0", > > + .codec_name = "codec-2", > > + .codec_dai_name = "codec-2-dai_name", > > + .platform_name = "samsung-i2s.0", > > + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > > + | SND_SOC_DAIFMT_CBM_CFM, > > + .ignore_suspend = 1, > > + .c2c_params = &dsp_codec_params, > > + .num_c2c_params = 1, > > + }, > > + { > > + .name = "DSP-CODEC", > > + .stream_name = "DSP-CODEC", > > + .cpu_dai_name = "wm0010-sdi2", > > + .codec_name = "codec-3", > > + .codec_dai_name = "codec-3-dai_name", > > + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > > + | SND_SOC_DAIFMT_CBM_CFM, > > + .ignore_suspend = 1, > > + .c2c_params = &dsp_codec_params, > > + .num_c2c_params = 1, > > + }, > > + }; > > + > > +This snippet draws inspiration from the configuration found in > > +``sound/soc/samsung/speyside.c``. The inclusion of the > > +``c2c_params`` indicates to the DAPM core that the DAI link is a > > +codec-to-codec connection. > > + > > +In the DAPM core, a route is established between the CPU DAI > > +playback widget and the codec DAI capture widget for playback, with > > +the reverse applying to the capture path. To trigger these routes, > > +DAPM requires valid endpoints, which can be either sink or source > > +widgets corresponding to the playback and capture paths, > > respectively. > > > > -In order to trigger this dai_link widget, a thin codec driver for > > -the speaker amp can be created as demonstrated in wm8727.c file, it > > -sets appropriate constraints for the device even if it needs no control. > > - > > -Make sure to name your corresponding cpu and codec playback and capture > > -dai names ending with "Playback" and "Capture" respectively as dapm core > > -will link and power those dais based on the name. > > - > > -A dai_link in a "simple-audio-card" will automatically be detected as > > -codec to codec when all DAIs on the link belong to codec components. > > -The dai_link will be initialized with the subset of stream parameters > > -(channels, format, sample rate) supported by all DAIs on the link. Since > > -there is no way to provide these parameters in the device tree, this is > > -mostly useful for communication with simple fixed-function codecs, such > > -as a Bluetooth controller or cellular modem. > > +To activate this DAI link widget, a lightweight codec driver for > > +the speaker amplifier can be implemented, following a similar > > +strategy to that in ``wm8727.c``. This driver should set the > > +necessary constraints for the device, even with minimal control > > +requirements. > > Would actually be nice to include the note that any codec driver > should be fine, the original text does kinda give the impression > one would have to write a "thin codec driver" but if you already > have a driver thin or otherwise that would be fine. Perhaps > better to rephrase as a codec driver being required. ok > > > + > > +It's crucial to append “Playback” and “Capture” suffixes to the > > +respective CPU and codec DAI names for playback and capture, as > > +the DAPM core links and powers these DAIs based on their naming > > +conventions. > > Are you sure this is true? I could be wrong but I don't expect > the naming is critical in hooking up a c2c DAI. tested this on my board and you are right. Will remove this. > > > + > > +In a codec-to-codec scenario involving multiple codecs (above > > +bootup logs are for multicodec scenario), it is not feasible to > > +control individual codecs using dummy kcontrols or DAPM widgets. > > I really am not sure what this means. What are we controlling > using dummy kcontrols? Why are we not using the real kcontrols > from the codec to control the codec? Our system includes a DSP that can generate audio(not audio to be honest but can be considered as a audio channel) independently, without CPU involvement. This audio needs to be sent to speakers via codecs, even when playback isn't occurring. We modeled all codecs as a C2C having one single snd_soc_dai_link with multiple codecs. So, now we can control all codecs using mixer control which we created as a part of C2C path completion. However, we got a new usecase where we shouldn't turn on all the codecs when mixer control is used for C2C, instead user should be able to specify which codec should get turned on. So, I attempted to add one more dummy mixer as part of C2C mixer path, follishly thinking that if the dummy mixer is not enabled, C2C won't allow the corresponding codec to get turned on. After reading the code, I saw that in C2C implementation it doesn't check for widget power status when turning on the path and nor check if the path is complete or not before calling the pcm ops. This is what I am listing as a drawback but I guess I can remove that as it is by design because we can probably have multiple snd_soc_dai_link C2C and then we can control them individually. > > > +This limitation arises because the CPU DAI is statically > > +connected to all codecs. Consequently, when a path is enabled, > > Which it shouldn't be? > > > +the DAPM core does not verify all the widgets that may be linked > > +to the mixer widget. It’s important to note that the mixer widget > > +serves as the trigger for these paths. > > + > > +Simple-audio-card configuration > > +---------------------------------- > > +A dai_link in a "simple-audio-card" will automatically be > > +detected as codec-to-codec when all DAIs on the link belong to > > +codec components. The dai_link will be initialized with the > > +subset of stream parameters (channels, format, sample rate) > > +supported by all DAIs on the link. Since there is no way to > > +provide these parameters in the device tree, this is mostly useful > > +for communication with simple fixed-function codecs, such as a > > +Bluetooth controller or cellular modem. > > -- > > 2.39.3 (Apple Git-146) > > > > > > Thanks, > Charles