[PATCH 00/13] Extend AHUB audio support for Tegra210 and later
Earlier as part of series [0], support for ADMAIF and I/O modules (such as I2S, DMIC and DSPK) was added. This series aims at exposing some of the AHUB internal modules (listed below), which can be used for audio pre or post processing.
* SFC (Sampling Frequency Converter) * MVC (Master Volume Control) * AMX (Audio Multiplexer) * ADX (Audio Demultiplexer) * Mixer
These modules can be plugged into audio paths and relevant processing can be done. The MUX routes are extended to allow add or remove above modules in the path via mixer controls. This is similar to how specific ADMAIF channels are connected to relevant I/O module instances at the moment.
Some of these modules can alter PCM parameters. Consider example of resampler (44.1 -> 48 kHz) in the path.
aplay(44.1 kHz) -> ADMAIF -> SFC -> (48 kHz) I2S -> (48kHz) Codec
The modules following SFC should be using converted sample rate and DAIs need to be configured accordingly. The audio-graph driver provides a mechanism to fixup the new parameters which can be specified in DT for a given DAI. Then core uses these new values via fixup callback and then pass it to respective DAIs hw_param() callback. The "convert-rate", described in [1], property can be used when there is rate conversion in the audio path. Similarly "convert-channels" can be used when there is channel conversion in the path. There is no "convert-xxx" property for sample size conversions. It can be added if necessary.
[0] https://www.lkml.org/lkml/2020/7/21/1357 [1] Documentation/devicetree/bindings/sound/audio-graph-port.yaml
Sameer Pujar (13): ASoC: soc-pcm: Don't reconnect an already active BE ASoC: simple-card-utils: Increase maximum DAI links limit to 512 ASoC: audio-graph: Fixup CPU endpoint hw_params in a BE<->BE link ASoC: dt-bindings: tegra: Few more Tegra210 AHUB modules ASoC: tegra: Add routes for few AHUB modules ASoC: tegra: Add Tegra210 based MVC driver ASoC: tegra: Add Tegra210 based SFC driver ASoC: tegra: Add Tegra210 based AMX driver ASoC: tegra: Add Tegra210 based ADX driver ASoC: tegra: Add Tegra210 based Mixer driver arm64: defconfig: Enable few Tegra210 based AHUB drivers arm64: tegra: Add few AHUB devices for Tegra210 and later arm64: tegra: Extend APE audio support on Jetson platforms
.../bindings/sound/nvidia,tegra210-adx.yaml | 74 + .../bindings/sound/nvidia,tegra210-ahub.yaml | 20 + .../bindings/sound/nvidia,tegra210-amx.yaml | 72 + .../bindings/sound/nvidia,tegra210-mixer.yaml | 67 + .../bindings/sound/nvidia,tegra210-mvc.yaml | 79 + .../bindings/sound/nvidia,tegra210-sfc.yaml | 76 + arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 1554 ++++++++- arch/arm64/boot/dts/nvidia/tegra186.dtsi | 120 + arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 1493 ++++++++- .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi | 1520 ++++++++- arch/arm64/boot/dts/nvidia/tegra194.dtsi | 116 + arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 876 +++++ arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 876 +++++ arch/arm64/boot/dts/nvidia/tegra210.dtsi | 77 + arch/arm64/configs/defconfig | 5 + include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 4 +- sound/soc/soc-pcm.c | 4 + sound/soc/tegra/Kconfig | 48 + sound/soc/tegra/Makefile | 10 + sound/soc/tegra/tegra210_adx.c | 527 +++ sound/soc/tegra/tegra210_adx.h | 72 + sound/soc/tegra/tegra210_ahub.c | 511 ++- sound/soc/tegra/tegra210_amx.c | 595 ++++ sound/soc/tegra/tegra210_amx.h | 93 + sound/soc/tegra/tegra210_mixer.c | 667 ++++ sound/soc/tegra/tegra210_mixer.h | 100 + sound/soc/tegra/tegra210_mvc.c | 629 ++++ sound/soc/tegra/tegra210_mvc.h | 117 + sound/soc/tegra/tegra210_sfc.c | 3542 ++++++++++++++++++++ sound/soc/tegra/tegra210_sfc.h | 78 + 31 files changed, 13601 insertions(+), 423 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml create mode 100644 sound/soc/tegra/tegra210_adx.c create mode 100644 sound/soc/tegra/tegra210_adx.h create mode 100644 sound/soc/tegra/tegra210_amx.c create mode 100644 sound/soc/tegra/tegra210_amx.h create mode 100644 sound/soc/tegra/tegra210_mixer.c create mode 100644 sound/soc/tegra/tegra210_mixer.h create mode 100644 sound/soc/tegra/tegra210_mvc.c create mode 100644 sound/soc/tegra/tegra210_mvc.h create mode 100644 sound/soc/tegra/tegra210_sfc.c create mode 100644 sound/soc/tegra/tegra210_sfc.h
In some cases, multiple FE components have the same BE component in their respective DPCM paths. One such example would be a mixer component, which can receive two or more inputs and sends a mixed output. In such cases, to avoid reconfiguration of already active DAI (mixer output DAI in this case), check the BE stream state to filter out the redundancy.
In summary, allow connection of BE if the respective current stream state is either NEW or CLOSED.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/soc-pcm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 48f71bb..e30cb5a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,6 +1395,10 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) + continue; + /* newly connected FE and BE */ err = dpcm_be_connect(fe, be, stream); if (err < 0) {
On 8/27/21 4:33 AM, Sameer Pujar wrote:
In some cases, multiple FE components have the same BE component in their respective DPCM paths. One such example would be a mixer component, which can receive two or more inputs and sends a mixed output. In such cases, to avoid reconfiguration of already active DAI (mixer output DAI in this case), check the BE stream state to filter out the redundancy.
In summary, allow connection of BE if the respective current stream state is either NEW or CLOSED.
This patch breaks our SOF CI tests, ironically in all cases where we have a mixer with a 'Deep buffer' port! The tests with multiple streams all fail with this error:
[ 124.366400] Port0 Deep Buffer: ASoC: no backend DAIs enabled for Port0 Deep Buffer [ 124.366406] Port0 Deep Buffer: ASoC: dpcm_fe_dai_prepare() failed (-22)
Reverting this patch restore the mixer functionality.
I see multiple problems with this patch:
At a high-level, there's at least a race condition where this BE state is checked without any protection. That was already a problem that I highlighted in a recent RFC and still working on, when we have multiple FEs we can have START/STOP triggers happening concurrently and it's necessary to serialize these triggers when checking the state, and this patch increases the 'surface' for this race condition.
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
I will agree this sort of mixer use cases is not well supported in soc-pcm.c, but let's not make it worse than it was before this patch, shall we?
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
[1] https://github.com/thesofproject/linux/pull/3177 [2] https://sof-ci.01.org/linuxpr/PR3177/build6440/devicetest/
Signed-off-by: Sameer Pujar spujar@nvidia.com
sound/soc/soc-pcm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 48f71bb..e30cb5a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,6 +1395,10 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
continue;
- /* newly connected FE and BE */ err = dpcm_be_connect(fe, be, stream); if (err < 0) {
On 9/29/2021 2:55 AM, Pierre-Louis Bossart wrote:
On 8/27/21 4:33 AM, Sameer Pujar wrote:
[...]
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
In your case, because of this patch, looks like the subsequent FE is not finding a BE DAI since it is already active due to a prior FE. The reason it works at my end is because the mixer input and output DAIs are separated. Any new FE would just configure the mixer input DAI to which it is attached and skip already running/configured output DAI. I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
1. The original issue at my end was not just a configuration redundancy. I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this may help (need to see what number is better), but does not address the redundancy problem.
2. If reconfiguration of the same BE is not necessary for a subsequent FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
On 29/09/2021 10:43, Sameer Pujar wrote:
On 9/29/2021 2:55 AM, Pierre-Louis Bossart wrote:
On 8/27/21 4:33 AM, Sameer Pujar wrote:
[...]
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
In your case, because of this patch, looks like the subsequent FE is not finding a BE DAI since it is already active due to a prior FE. The reason it works at my end is because the mixer input and output DAIs are separated. Any new FE would just configure the mixer input DAI to which it is attached and skip already running/configured output DAI.
The problem as I see is that with this patch one can not connect a new FE to a BE which is _not_ in NEW or CLOSE state.
The FE and BE needs to be connected to have DPCM working and this patch makes the code to skip the dpcm_be_connect().
Consider this simple setup:
FE1 -->| | --> BE --> FE2- ->|
First we start FE1, dpcm_be_connect(FE1, BE, stream) is made.
Later FE2 is started but dpcm_be_connect(FE2, BE, stream) would be not made because BE is no longer in NEW/CLOSE state.
I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
- The original issue at my end was not just a configuration redundancy.
I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this may help (need to see what number is better), but does not address the redundancy problem.
- If reconfiguration of the same BE is not necessary for a subsequent
FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
I'm not sure, but it might be possible to just skip the dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE); call at the end of the loop, but the question is under which condition? Can a BE asked to be reconfigured when STOP/OPEN/HW_PARAMS?
Skipping the connect does not sound right for a new FE-BE connection.
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
Can you describe the sequence that you used to start them? That may be useful to understand the criteria you used?
In your case, because of this patch, looks like the subsequent FE is not finding a BE DAI since it is already active due to a prior FE. The reason it works at my end is because the mixer input and output DAIs are separated. Any new FE would just configure the mixer input DAI to which it is attached and skip already running/configured output DAI.
If you want to visualize the topology we're using in our 'nocodec' tests, see
https://sof-ci.01.org/linuxpr/PR3177/build6440/devicetest/?model=ADLP_RVP_NO...
and use the sof-adl-nocodec.
it's a bog-standard topology with processing entities connected by buffers.
I don't fully understand the notion of mixer input DAI, in our case we have a bunch of PCM devices connected to a mixer. The mixer is not directly connected to a DAI.
The problem as I see is that with this patch one can not connect a new FE to a BE which is _not_ in NEW or CLOSE state.
The FE and BE needs to be connected to have DPCM working and this patch makes the code to skip the dpcm_be_connect().
Consider this simple setup:
FE1 -->| | --> BE --> FE2- ->|
First we start FE1, dpcm_be_connect(FE1, BE, stream) is made.
Later FE2 is started but dpcm_be_connect(FE2, BE, stream) would be not made because BE is no longer in NEW/CLOSE state.
I share Peter's analysis, there cannot be any restrictions on connections - at any time. A mixer input might become active and be added to the mix. We might have a temporary lock to delay new connections but cannot not reject them outright based on BE state.
I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
That's a different question - and a good one.
In the case of a mixer, the propagation of hw_params is a broken concept. It leads to the first FE configuring the BE to define its preferred parameters, e.g. S16_LE format. If later on a second FE is started which could play S24_LE, the mixer and BE are already configured to a lower resolution. A mixer should really have its own parameters and be the start of a new 'domain' - as Lars described it several years ago at the audio miniconference.
For now, the only restriction that we could enforce is that the BE cannot be reconfigured after the prepare step.
Note that our DAIs tolerate multiple calls to hw_params. If you have a case where the hw_params allocates resources, maybe you should consider moving that allocation to the prepare step, or free them if you detect a reconfiguration. That would be something needed even outside of the DPCM scope. Similarly you need to support the case where the DAI hw_free is called without hw_params ever being called, it's a known sequence that can happen if the FE hw-params fails.
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
- The original issue at my end was not just a configuration redundancy.
I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this may help (need to see what number is better), but does not address the redundancy problem.
we haven't used more than 2 users, but it's already broken at 2 with race conditions left and right. I am really surprised you managed to have more than 2 without hitting inconsistent states - our automated play/stop/pause monkey tests reliably break DPCM in less than 20s.
- If reconfiguration of the same BE is not necessary for a subsequent
FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
I'm not sure, but it might be possible to just skip the dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE); call at the end of the loop, but the question is under which condition? Can a BE asked to be reconfigured when STOP/OPEN/HW_PARAMS?
Skipping the connect does not sound right for a new FE-BE connection.
The reconfiguration is one problem, but what also happens is that the BE dailink will see multiple triggers. I've been playing with refcounts to force consistency and make sure there is only one TRIGGER_START send to the dailink, and conversely there are cases where the TRIGGER_STOP is never sent...
On 9/29/2021 8:22 PM, Pierre-Louis Bossart wrote:
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
Can you describe the sequence that you used to start them? That may be useful to understand the criteria you used?
I have something like this:
FE1 --> Crossbar -> Mixer Input1 | FE2 --> Crossbar -> Mixer Input2 | ... | --> Mixer Output --> ... | FE10 --> Crossbar -> Mixer Input10 |
All these FEs are started one after the other. This is an example of 10x1. Similarly we can have 2x1, 3x1 etc., In our system, the crossbar [0] and mixer [1] are separate ASoC components. Basically audio paths consist of a group of ASoC components which are connected back to back.
[0] https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git/tree/sound... [1] https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git/tree/sound...
[...]
I don't fully understand the notion of mixer input DAI, in our case we have a bunch of PCM devices connected to a mixer. The mixer is not directly connected to a DAI.
Please see above mixer example. Since mixer is a separate ASoC component, it exposes 10 inputs (or DAIs) and outputs. Originally what I wanted to do was, for subsequent FE runs (FE2, FE3 ...) mixer output need not be configured again and again.
The problem as I see is that with this patch one can not connect a new FE to a BE which is _not_ in NEW or CLOSE state.
The FE and BE needs to be connected to have DPCM working and this patch makes the code to skip the dpcm_be_connect().
Consider this simple setup:
FE1 -->| | --> BE --> FE2- ->|
First we start FE1, dpcm_be_connect(FE1, BE, stream) is made.
Later FE2 is started but dpcm_be_connect(FE2, BE, stream) would be not made because BE is no longer in NEW/CLOSE state.
I share Peter's analysis, there cannot be any restrictions on connections - at any time. A mixer input might become active and be added to the mix. We might have a temporary lock to delay new connections but cannot not reject them outright based on BE state.
Yes, I understand how this affects a system like yours. As per mixer example above, in our case subsequent FEs always find BE from Crossbar. That is why I don't see similar error.
I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
That's a different question - and a good one.
In the case of a mixer, the propagation of hw_params is a broken concept. It leads to the first FE configuring the BE to define its preferred parameters, e.g. S16_LE format. If later on a second FE is started which could play S24_LE, the mixer and BE are already configured to a lower resolution. A mixer should really have its own parameters and be the start of a new 'domain' - as Lars described it several years ago at the audio miniconference.
Propagation is one of the problems we want to address and require help from DPCM experts. But the scenario you mentioned is a special case which need not be supported, because mixer can operate in one configuration at a given time and subsequent FEs should agree to the already running configuration. However mixer should support both S16_LE and S24_LE (whenever possible), but not simultaneously. At least this is the expecation from our systems. Yes mixer may require fixup of a specific config (we earlier had proposed mixer controls to configure mixer parameters, but the idea was disliked), but propagation may help avoid fixing up everywhere in the audio path where it is not really required. But I don't know how this can be done at the moment.
For now, the only restriction that we could enforce is that the BE cannot be reconfigured after the prepare step.
Note that our DAIs tolerate multiple calls to hw_params. If you have a case where the hw_params allocates resources, maybe you should consider moving that allocation to the prepare step, or free them if you detect a reconfiguration. That would be something needed even outside of the DPCM scope. Similarly you need to support the case where the DAI hw_free is called without hw_params ever being called, it's a known sequence that can happen if the FE hw-params fails.
Currently this does not seem to be a problem for us. Patch was to avoid reconfiguration which was felt to be redundant for our system.
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
- The original issue at my end was not just a configuration redundancy.
I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this
may help (need to see what number is better), but does not address the redundancy problem.
we haven't used more than 2 users, but it's already broken at 2 with race conditions left and right. I am really surprised you managed to have more than 2 without hitting inconsistent states - our automated play/stop/pause monkey tests reliably break DPCM in less than 20s.
I am not sure what is the exact difference, may be DPCM usage in our case is different from what you have. I have mixer tests for different combinations (2x1, 3x1 ...), which seem to pass. In general, we want to have path like this.
FE -> BE1 -> BE2 -> ... -> BEx
Each BEx could be a mixer, resampler etc., Currently DPCM core sees this as multiple BEs for a given FE and that is why multiple "users" are reported.
In the interim, may be we can have following patch to keep both systems working and keep the discussion going to address the oustanding requirements/issues?
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ab25f99..0fbab50 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,7 +1395,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + /* + * Filter for systems with 'component_chaining' enabled. + * This helps to avoid unnecessary re-configuration of an + * already active BE on such systems. + */ + if (fe->card->component_chaining && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue;
- If reconfiguration of the same BE is not necessary for a subsequent
FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
I'm not sure, but it might be possible to just skip the dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE); call at the end of the loop, but the question is under which condition? Can a BE asked to be reconfigured when STOP/OPEN/HW_PARAMS?
Skipping the connect does not sound right for a new FE-BE connection.
The reconfiguration is one problem, but what also happens is that the BE dailink will see multiple triggers. I've been playing with refcounts to force consistency and make sure there is only one TRIGGER_START send to the dailink, and conversely there are cases where the TRIGGER_STOP is never sent...
Just a thought. FE links have dummy codec DAI and core wants to find a real BE when FE is started. May be don't fail a FE when no back end DAI is found (and/or find if the same BE is already connected to some FE) and the above problem becomes simpler?
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
Can you describe the sequence that you used to start them? That may be useful to understand the criteria you used?
I have something like this:
FE1 --> Crossbar -> Mixer Input1 | FE2 --> Crossbar -> Mixer Input2 | ... | --> Mixer Output --> ... | FE10 --> Crossbar -> Mixer Input10 |
All these FEs are started one after the other. This is an example of 10x1. Similarly we can have 2x1, 3x1 etc., In our system, the crossbar [0] and mixer [1] are separate ASoC components. Basically audio paths consist of a group of ASoC components which are connected back to back.
Not following. Can you explain how starting FE1 does not change the state of the mixer output then?
Or is each 'Crossbar' instance a full-blown BE? In that case you have a 1:1 mapping between FE and BE, a *really* simple topology...
I don't fully understand the notion of mixer input DAI, in our case we have a bunch of PCM devices connected to a mixer. The mixer is not directly connected to a DAI.
Please see above mixer example. Since mixer is a separate ASoC component, it exposes 10 inputs (or DAIs) and outputs. Originally what I wanted to do was, for subsequent FE runs (FE2, FE3 ...) mixer output need not be configured again and again.
The problem as I see is that with this patch one can not connect a new FE to a BE which is _not_ in NEW or CLOSE state.
The FE and BE needs to be connected to have DPCM working and this patch makes the code to skip the dpcm_be_connect().
Consider this simple setup:
FE1 -->| | --> BE --> FE2- ->|
First we start FE1, dpcm_be_connect(FE1, BE, stream) is made.
Later FE2 is started but dpcm_be_connect(FE2, BE, stream) would be not made because BE is no longer in NEW/CLOSE state.
I share Peter's analysis, there cannot be any restrictions on connections - at any time. A mixer input might become active and be added to the mix. We might have a temporary lock to delay new connections but cannot not reject them outright based on BE state.
Yes, I understand how this affects a system like yours. As per mixer example above, in our case subsequent FEs always find BE from Crossbar. That is why I don't see similar error.
Not following either.
I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
That's a different question - and a good one.
In the case of a mixer, the propagation of hw_params is a broken concept. It leads to the first FE configuring the BE to define its preferred parameters, e.g. S16_LE format. If later on a second FE is started which could play S24_LE, the mixer and BE are already configured to a lower resolution. A mixer should really have its own parameters and be the start of a new 'domain' - as Lars described it several years ago at the audio miniconference.
Propagation is one of the problems we want to address and require help from DPCM experts. But the scenario you mentioned is a special case which need not be supported, because mixer can operate in one configuration at a given time and subsequent FEs should agree to the already running configuration. However mixer should support both S16_LE and S24_LE (whenever possible), but not simultaneously. At least this is the expecation from our systems. Yes mixer may require fixup of a specific config (we earlier had proposed mixer controls to configure mixer parameters, but the idea was disliked), but propagation may help avoid fixing up everywhere in the audio path where it is not really required. But I don't know how this can be done at the moment.
What I am saying is that the mixer should be pre-configured with the desired resolution/sample rate, and some adaptation needs to happen if the FE provides data in a different format.
This is similar to what sound servers typically do on their sinks, they define ONE configuration. Dynamic changes are annoying and result in corner cases where the quality can vary depending on which FE is started first.
For now, the only restriction that we could enforce is that the BE
cannot be reconfigured after the prepare step.
Note that our DAIs tolerate multiple calls to hw_params. If you have a case where the hw_params allocates resources, maybe you should consider moving that allocation to the prepare step, or free them if you detect a reconfiguration. That would be something needed even outside of the DPCM scope. Similarly you need to support the case where the DAI hw_free is called without hw_params ever being called, it's a known sequence that can happen if the FE hw-params fails.
Currently this does not seem to be a problem for us. Patch was to avoid reconfiguration which was felt to be redundant for our system.
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
- The original issue at my end was not just a configuration
redundancy. I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this may help (need to see what number is better), but does not address the redundancy problem.
we haven't used more than 2 users, but it's already broken at 2 with race conditions left and right. I am really surprised you managed to have more than 2 without hitting inconsistent states - our automated play/stop/pause monkey tests reliably break DPCM in less than 20s.
I am not sure what is the exact difference, may be DPCM usage in our case is different from what you have. I have mixer tests for different combinations (2x1, 3x1 ...), which seem to pass. In general, we want to have path like this.
FE -> BE1 -> BE2 -> ... -> BEx
Each BEx could be a mixer, resampler etc., Currently DPCM core sees this as multiple BEs for a given FE and that is why multiple "users" are reported.
This sort of flow vastly exceeds the capabilities of DPCM, which is already badly broken with one BE and 2 FEs... I think what you want is what Lars described at the audio miniconf with 'domains'.
In the interim, may be we can have following patch to keep both systems working and keep the discussion going to address the oustanding requirements/issues?
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ab25f99..0fbab50 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,7 +1395,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + /* + * Filter for systems with 'component_chaining' enabled. + * This helps to avoid unnecessary re-configuration of an + * already active BE on such systems. + */ + if (fe->card->component_chaining && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue;
that wouldn't work. We need to support the STOP and START cases as well.
- If reconfiguration of the same BE is not necessary for a subsequent
FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
I'm not sure, but it might be possible to just skip the dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE); call at the end of the loop, but the question is under which condition? Can a BE asked to be reconfigured when STOP/OPEN/HW_PARAMS?
Skipping the connect does not sound right for a new FE-BE connection.
The reconfiguration is one problem, but what also happens is that the BE dailink will see multiple triggers. I've been playing with refcounts to force consistency and make sure there is only one TRIGGER_START send to the dailink, and conversely there are cases where the TRIGGER_STOP is never sent...
Just a thought. FE links have dummy codec DAI and core wants to find a real BE when FE is started. May be don't fail a FE when no back end DAI is found (and/or find if the same BE is already connected to some FE) and the above problem becomes simpler?
That would be just moving the problem. In our case we would be silently playing on a dummy output just because the correct output was not found due to state handling issues.
On 9/30/2021 8:04 PM, Pierre-Louis Bossart wrote:
But in addition we'd need to agree on what an 'active BE' is. Why can't we connect a second stream while the first one is already in HW_PARAMS or PAUSED or STOP? It's perfectly legal in ALSA/ASoC to have multiple HW_PARAMS calls, and when we reach STOP we have to do a prepare again.
And more fundamentally, the ability to add a second FE on a 'active' BE in START state is a basic requirement for a mixer, e.g. to play a notification on one FE while listening to music on another. What needs to happen is only to make sure that the FE and BE are compatible in terms of HW_PARAMS and not sending a second TRIGGER_STOP, only checking the BE NEW or CLOSE state is way too restrictive.
Sorry for the trouble to your system.
Idea was to avoid reconfiguration of the same BE DAI again, but not to stop the provision to add a subsequent FE. In fact I had tested mixing of streams coming from 10 different FEs.
Can you describe the sequence that you used to start them? That may be useful to understand the criteria you used?
I have something like this:
FE1 --> Crossbar -> Mixer Input1 | FE2 --> Crossbar -> Mixer Input2 | ... | --> Mixer Output --> ... | FE10 --> Crossbar -> Mixer Input10 |
All these FEs are started one after the other. This is an example of 10x1. Similarly we can have 2x1, 3x1 etc., In our system, the crossbar [0] and mixer [1] are separate ASoC components. Basically audio paths consist of a group of ASoC components which are connected back to back.
Not following. Can you explain how starting FE1 does not change the state of the mixer output then?
Or is each 'Crossbar' instance a full-blown BE? In that case you have a 1:1 mapping between FE and BE, a *really* simple topology...
Yes 'Crossbar' exposes multiple ports and it is 1:1 mapping with FE. Starting FE1 does configure mixer output.
I don't fully understand the notion of mixer input DAI, in our case we have a bunch of PCM devices connected to a mixer. The mixer is not directly connected to a DAI.
Please see above mixer example. Since mixer is a separate ASoC component, it exposes 10 inputs (or DAIs) and outputs. Originally what I wanted to do was, for subsequent FE runs (FE2, FE3 ...) mixer output need not be configured again and again.
The problem as I see is that with this patch one can not connect a new FE to a BE which is _not_ in NEW or CLOSE state.
The FE and BE needs to be connected to have DPCM working and this patch makes the code to skip the dpcm_be_connect().
Consider this simple setup:
FE1 -->| | --> BE --> FE2- ->|
First we start FE1, dpcm_be_connect(FE1, BE, stream) is made.
Later FE2 is started but dpcm_be_connect(FE2, BE, stream) would be not made because BE is no longer in NEW/CLOSE state.
I share Peter's analysis, there cannot be any restrictions on connections - at any time. A mixer input might become active and be added to the mix. We might have a temporary lock to delay new connections but cannot not reject them outright based on BE state.
Yes, I understand how this affects a system like yours. As per mixer example above, in our case subsequent FEs always find BE from Crossbar. That is why I don't see similar error.
Not following either.
May be it is understandable now with above crossbar point?
I am just curious to know, if originally you were reconfiguring the BE DAI again with same parameters (for a second FE) or some additional configuration is done?
That's a different question - and a good one.
In the case of a mixer, the propagation of hw_params is a broken concept. It leads to the first FE configuring the BE to define its preferred parameters, e.g. S16_LE format. If later on a second FE is started which could play S24_LE, the mixer and BE are already configured to a lower resolution. A mixer should really have its own parameters and be the start of a new 'domain' - as Lars described it several years ago at the audio miniconference.
Propagation is one of the problems we want to address and require help from DPCM experts. But the scenario you mentioned is a special case which need not be supported, because mixer can operate in one configuration at a given time and subsequent FEs should agree to the already running configuration. However mixer should support both S16_LE and S24_LE (whenever possible), but not simultaneously. At least this is the expecation from our systems. Yes mixer may require fixup of a specific config (we earlier had proposed mixer controls to configure mixer parameters, but the idea was disliked), but propagation may help avoid fixing up everywhere in the audio path where it is not really required. But I don't know how this can be done at the moment.
What I am saying is that the mixer should be pre-configured with the desired resolution/sample rate, and some adaptation needs to happen if the FE provides data in a different format.
This is similar to what sound servers typically do on their sinks, they define ONE configuration. Dynamic changes are annoying and result in corner cases where the quality can vary depending on which FE is started first.
When there are multiple FEs running, yes it is better to run on a pre-agreed configuration to minimize the side effects of race between FEs. Also there should also be a provision where mixer params directly depend on FEs. For example, a 2x1 mixer can mix two 16-bit streams at one time and the other time it can mix two 32-bit streams.
[...]
I can send a revert with the explanations in the commit message if there is a consensus that this patch needs to be revisited.
May be this can be revisited since it appears to be a critical problem for your system. But I hope this discussion can be alive on following points for a better fix.
- The original issue at my end was not just a configuration
redundancy. I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this
may help (need to see what number is better), but does not address the redundancy problem.
we haven't used more than 2 users, but it's already broken at 2 with race conditions left and right. I am really surprised you managed to have more than 2 without hitting inconsistent states - our automated play/stop/pause monkey tests reliably break DPCM in less than 20s.
I am not sure what is the exact difference, may be DPCM usage in our case is different from what you have. I have mixer tests for different combinations (2x1, 3x1 ...), which seem to pass. In general, we want to have path like this.
FE -> BE1 -> BE2 -> ... -> BEx
Each BEx could be a mixer, resampler etc., Currently DPCM core sees this as multiple BEs for a given FE and that is why multiple "users" are reported.
This sort of flow vastly exceeds the capabilities of DPCM, which is already badly broken with one BE and 2 FEs... I think what you want is what Lars described at the audio miniconf with 'domains'.
May be the core would require enhancements to fully support such scheme. But so far the system is running well for below path: FE -> BE1 (crossbar) -> BE2 (I2S) -> BE3 (external codec)
I could introduce more BEs like resampler or mixer in the path and results seem to be good.
BTW, I don't know what 'domains' mean. I will be curious to know what this exactly is. If someone is already using it, a usage reference can help.
In the interim, may be we can have following patch to keep both systems working and keep the discussion going to address the oustanding requirements/issues?
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ab25f99..0fbab50 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,7 +1395,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
/*
* Filter for systems with 'component_chaining' enabled.
* This helps to avoid unnecessary re-configuration of an
* already active BE on such systems.
*/
if (fe->card->component_chaining &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue;
that wouldn't work. We need to support the STOP and START cases as well.
I meant with flag 'fe->card->component_chaining', which is currently used by Tegra audio only.
- If reconfiguration of the same BE is not necessary for a subsequent
FE run, shouldn't we avoid the reconfig itself and somehow avoid FE failure?
I'm not sure, but it might be possible to just skip the dpcm_set_be_update_state(be, stream, SND_SOC_DPCM_UPDATE_BE); call at the end of the loop, but the question is under which condition? Can a BE asked to be reconfigured when STOP/OPEN/HW_PARAMS?
Skipping the connect does not sound right for a new FE-BE connection.
The reconfiguration is one problem, but what also happens is that the BE dailink will see multiple triggers. I've been playing with refcounts to force consistency and make sure there is only one TRIGGER_START send to the dailink, and conversely there are cases where the TRIGGER_STOP is never sent...
Just a thought. FE links have dummy codec DAI and core wants to find a real BE when FE is started. May be don't fail a FE when no back end DAI is found (and/or find if the same BE is already connected to some FE) and the above problem becomes simpler?
That would be just moving the problem. In our case we would be silently playing on a dummy output just because the correct output was not found due to state handling issues.
OK. In our case, application would report error since the frames would never get consumed for given FE due to unavailable BE.
Can you describe the sequence that you used to start them? That may be useful to understand the criteria you used?
I have something like this:
FE1 --> Crossbar -> Mixer Input1 | FE2 --> Crossbar -> Mixer Input2 | ... | --> Mixer Output --> ... | FE10 --> Crossbar -> Mixer Input10 |
All these FEs are started one after the other. This is an example of 10x1. Similarly we can have 2x1, 3x1 etc., In our system, the crossbar [0] and mixer [1] are separate ASoC components. Basically audio paths consist of a group of ASoC components which are connected back to back.
Not following. Can you explain how starting FE1 does not change the state of the mixer output then?
Or is each 'Crossbar' instance a full-blown BE? In that case you have a 1:1 mapping between FE and BE, a *really* simple topology...
Yes 'Crossbar' exposes multiple ports and it is 1:1 mapping with FE. Starting FE1 does configure mixer output.
Ah ok, now I get the difference with the N:1 topology we used. Thanks for explaining this.
In the interim, may be we can have following patch to keep both systems working and keep the discussion going to address the oustanding requirements/issues?
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ab25f99..0fbab50 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1395,7 +1395,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, if (!fe->dpcm[stream].runtime && !fe->fe_compr) continue;
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && + /* + * Filter for systems with 'component_chaining' enabled. + * This helps to avoid unnecessary re-configuration of an + * already active BE on such systems. + */ + if (fe->card->component_chaining && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE)) continue;
that wouldn't work. We need to support the STOP and START cases as well.
I meant with flag 'fe->card->component_chaining', which is currently used by Tegra audio only.
Ah yes, this may be a temporary solution that gets us both back to a 'working solution'. Let me give it a try. Good discussion, thanks! -Pierre
- The original issue at my end was not just a configuration redundancy.
I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this may help (need to see what number is better), but does not address the redundancy problem.
Going back to this DPCM_MAX_BE_USERS definition, it seems rather arbitrary and not so useful indeed.
/* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); continue; }
The comment is no longer aligned with the code, wondering if this is a feature or a bug. There's no reason to arbitrarily restrict the number of users of a BE, or the check would need to use platform-specific information such as the number of inputs/outputs supported by a mixer/demux.
Maybe Morimoto-san can comment since this was added in:
1db19c151819 ('ASoC: soc-pcm: fixup dpcm_be_dai_startup() user count')
We're not done with soc-pcm.c cleanups :-)
On 10/1/2021 12:30 AM, Pierre-Louis Bossart wrote:
- The original issue at my end was not just a configuration redundancy.
I realize now that with more stream addition following error print is seen. "ASoC: too many users playback at open 4"
This is because the max DPCM users is capped at 8. Increasing this
may help (need to see what number is better), but does not address the redundancy problem.
Going back to this DPCM_MAX_BE_USERS definition, it seems rather arbitrary and not so useful indeed.
/* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); continue; }
The comment is no longer aligned with the code, wondering if this is a feature or a bug.
Looks like the comment is misplaced and the intention might have been to place it like below?
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e30cb5a..5cb5019 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1508,7 +1508,6 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue;
- /* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", @@ -1516,6 +1515,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) continue; }
+ /* first time the dpcm is open ? */ if (be->dpcm[stream].users++ != 0) continue;
There's no reason to arbitrarily restrict the number of users of a BE, or the check would need to use platform-specific information such as the number of inputs/outputs supported by a mixer/demux.
Maybe Morimoto-san can comment since this was added in:
1db19c151819 ('ASoC: soc-pcm: fixup dpcm_be_dai_startup() user count')
We're not done with soc-pcm.c cleanups :-)
The current limit of 128 is not sufficient when more components are added to the audio map on Tegra210 and later platforms. Thus it is resulting in probe failure.
The requirement is of nearly ~200 DAI links. To give sufficient room for future additions the maximum limit is increased to 512 DAI links. This is a preparatory patch to add more components like resampler, mixer, multiplexers, demultiplexers and volume controllers to Tegra210 and later platforms.
Signed-off-by: Sameer Pujar spujar@nvidia.com Cc: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- include/sound/simple_card_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 51b3b48..6b78034 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -115,7 +115,7 @@ struct asoc_simple_priv { ((codec) = simple_props_to_dai_codec(props, i)); \ (i)++)
-#define SNDRV_MAX_LINKS 128 +#define SNDRV_MAX_LINKS 512
struct link_info { int link; /* number of link */
When multiple components are connected back to back in an audio path, hw_param fixup may be required for CPU or Codec endpoint of BE<->BE DAI links. Currently fixup support is available for Codec and this commit adds similar feature for CPU endpoint of a BE<->BE link.
For example a resampler component can be plugged into an audio path. [ FE -> BE1 -> ... -> resampler -> ... BEn ]
The resampler DAI links can be: BEx (CPU) -> resampler input (Codec) resampler output (CPU) -> BEy (Codec)
Thus input and output sample rate parameters for resampler can be fixed up as per the resample requirement.
Signed-off-by: Sameer Pujar spujar@nvidia.com Cc: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/generic/audio-graph-card.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 5e71382..7439122 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -309,8 +309,10 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where * there are 'n' BE components in the path. */ - if (card->component_chaining && !soc_component_is_pcm(cpus)) + if (card->component_chaining && !soc_component_is_pcm(cpus)) { dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; + }
asoc_simple_canonicalize_cpu(cpus, is_single_links); } else {
This patch adds YAML schema for DT bindings of few AHUB modules. These devices will be registered as ASoC components and bindings will be used on Tegra210 and later chips. The bindings for below mentioned modules are added:
* SFC (Sampling Frequency Converter) * MVC (Master Volume Control) * AMX (Audio Multiplexer) * ADX (Audio Demultiplexer) * Mixer
Signed-off-by: Sameer Pujar spujar@nvidia.com Cc: Rob Herring robh+dt@kernel.org --- .../bindings/sound/nvidia,tegra210-adx.yaml | 74 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-ahub.yaml | 20 ++++++ .../bindings/sound/nvidia,tegra210-amx.yaml | 72 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mixer.yaml | 67 ++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mvc.yaml | 79 ++++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-sfc.yaml | 76 +++++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml new file mode 100644 index 0000000..9950585 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-adx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 ADX Device Tree Bindings + +description: | + The Audio Demultiplexer (ADX) block takes an input stream with up to + 16 channels and demultiplexes it into four output streams of up to 16 + channels each. A byte RAM helps to form output frames by any combination + of bytes from the input frame. Its design is identical to that of byte + RAM in the AMX except that the data flow direction is reversed. + +maintainers: + - Jon Hunter jonathanh@nvidia.com + - Mohan Kumar mkumard@nvidia.com + - Sameer Pujar spujar@nvidia.com + +properties: + $nodename: + pattern: "^adx@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-adx + - items: + - enum: + - nvidia,tegra194-adx + - nvidia,tegra186-adx + - const: nvidia,tegra210-adx + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^ADX[1-9]$" + $ref: /schemas/types.yaml#/definitions/string + description: + used as prefix for sink/source names of the component. Must be a + unique string among multiple instances of the same component. + The name can be "ADX1" or "ADX2" ... "ADXx", where x depends on + the maximum available instances on a Tegra SoC. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + ADX has one input and four output. Accordingly ACIF (Audio Client + Interface) RX and TX port nodes are defined to represent ADX inputs + and output respectively. These are connected to corresponding ports + on AHUB. + + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + adx@702d3800 { + compatible = "nvidia,tegra210-adx"; + reg = <0x702d3800 0x100>; + sound-name-prefix = "ADX1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml index 1118a94..4087eeb 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml @@ -85,6 +85,26 @@ patternProperties: type: object $ref: nvidia,tegra186-dspk.yaml#
+ '^mvc@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-mvc.yaml# + + '^sfc@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-sfc.yaml# + + '^amx@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-amx.yaml# + + '^adx@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-adx.yaml# + + '^mixer@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-mixer.yaml# + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml new file mode 100644 index 0000000..e6b365b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-amx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 AMX Device Tree Bindings + +description: | + The Audio Multiplexer (AMX) block can multiplex up to four input streams + each of which can have maximum 16 channels and generate an output stream + with maximum 16 channels. A byte RAM helps to form an output frame by + any combination of bytes from the input frames. + +maintainers: + - Jon Hunter jonathanh@nvidia.com + - Mohan Kumar mkumard@nvidia.com + - Sameer Pujar spujar@nvidia.com + +properties: + $nodename: + pattern: "^amx@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-amx + - items: + - const: nvidia,tegra186-amx + - const: nvidia,tegra210-amx + - const: nvidia,tegra194-amx + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^AMX[1-9]$" + $ref: /schemas/types.yaml#/definitions/string + description: + used as prefix for sink/source names of the component. Must be a + unique string among multiple instances of the same component. + The name can be "AMX1" or "AMX2" ... "AMXx", where x depends on + the maximum available instances on a Tegra SoC. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + AMX has four inputs and one output. Accordingly ACIF (Audio Client + Interfaces) RX and TX port nodes are defined to represent AMX inputs + and output respectively. These are connected to corresponding ports + on AHUB. + + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + amx@702d3000 { + compatible = "nvidia,tegra210-amx"; + reg = <0x702d3000 0x100>; + sound-name-prefix = "AMX1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml new file mode 100644 index 0000000..0808355 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mixer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 Mixer Device Tree Bindings + +description: | + The Mixer supports mixing of up to ten 7.1 audio input streams and + generate five outputs (each of which can be any combination of the + ten input streams). + +maintainers: + - Jon Hunter jonathanh@nvidia.com + - Mohan Kumar mkumard@nvidia.com + - Sameer Pujar spujar@nvidia.com + +properties: + $nodename: + pattern: "^mixer@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-amixer + - items: + - enum: + - nvidia,tegra194-amixer + - nvidia,tegra186-amixer + - const: nvidia,tegra210-amixer + + reg: + maxItems: 1 + + sound-name-prefix: + const: "MIXER" + $ref: /schemas/types.yaml#/definitions/string + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + Mixer has ten inputs and five outputs. Accordingly ACIF (Audio Client + Interfaces) RX and TX port nodes are defined to represent MIXER inputs + and outputs respectively. These are connected to corresponding ports + on AHUB. + + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + mixer@702dbb00 { + compatible = "nvidia,tegra210-amixer"; + reg = <0x702dbb00 0x800>; + sound-name-prefix = "MIXER"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml new file mode 100644 index 0000000..7d81b11 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mvc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 MVC Device Tree Bindings + +description: | + The Master Volume Control (MVC) provides gain or attenuation to a digital + signal path. It can be used in input or output signal path for per-stream + volume control or it can be used as master volume control. The MVC block + has one input and one output. The input digital stream can be mono or + multi-channel (up to 7.1 channels) stream. An independent mute control is + also included in the MVC block. + +maintainers: + - Jon Hunter jonathanh@nvidia.com + - Mohan Kumar mkumard@nvidia.com + - Sameer Pujar spujar@nvidia.com + +properties: + $nodename: + pattern: "^mvc@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-mvc + - items: + - enum: + - nvidia,tegra194-mvc + - nvidia,tegra186-mvc + - const: nvidia,tegra210-mvc + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^MVC[1-9]$" + $ref: /schemas/types.yaml#/definitions/string + description: + used as prefix for sink/source names of the component. Must be a + unique string among multiple instances of the same component. + The name can be "MVC1" or "MVC2" ... "MVCx", where x depends on + the maximum available instances on a Tegra SoC. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + ACIF (Audio Client Interface) acting as MVC input (RX) port. + This is connected to corresponding ACIF port on AHUB. + + port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + ACIF (Audio Client Interface) acting as MVC output (TX) port. + This is connected to corresponding ACIF port on AHUB. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + mvc@702da000 { + compatible = "nvidia,tegra210-mvc"; + reg = <0x702da000 0x200>; + sound-name-prefix = "MVC1"; + }; + +... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml new file mode 100644 index 0000000..5f05e2a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-sfc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tegra210 SFC Device Tree Bindings + +description: | + The Sampling Frequency Converter (SFC) converts the sampling frequency + of the input signal from one frequency to another. It supports sampling + frequency conversions of streams of up to two channels (stereo). + +maintainers: + - Jon Hunter jonathanh@nvidia.com + - Mohan Kumar mkumard@nvidia.com + - Sameer Pujar spujar@nvidia.com + +properties: + $nodename: + pattern: "^sfc@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra210-sfc + - items: + - enum: + - nvidia,tegra194-sfc + - nvidia,tegra186-sfc + - const: nvidia,tegra210-sfc + + reg: + maxItems: 1 + + sound-name-prefix: + pattern: "^SFC[1-9]$" + $ref: /schemas/types.yaml#/definitions/string + description: + used as prefix for sink/source names of the component. Must be a + unique string among multiple instances of the same component. + The name can be "SFC1" or "SFC2" ... "SFCx", where x depends on + the maximum available instances on a Tegra SoC. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + ACIF (Audio Client Interface) acting as SFC input (RX) port. + This is connected to corresponding ACIF port on AHUB. + + port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: | + ACIF (Audio Client Interface) acting as SFC output (TX) port. + This is connected to corresponding ACIF port on AHUB. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + sfc@702d2000 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2000 0x200>; + sound-name-prefix = "SFC1"; + }; + +...
On Fri, Aug 27, 2021 at 03:03:50PM +0530, Sameer Pujar wrote:
This patch adds YAML schema for DT bindings of few AHUB modules. These devices will be registered as ASoC components and bindings will be used on Tegra210 and later chips. The bindings for below mentioned modules are added:
- SFC (Sampling Frequency Converter)
- MVC (Master Volume Control)
- AMX (Audio Multiplexer)
- ADX (Audio Demultiplexer)
- Mixer
Signed-off-by: Sameer Pujar spujar@nvidia.com Cc: Rob Herring robh+dt@kernel.org
.../bindings/sound/nvidia,tegra210-adx.yaml | 74 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-ahub.yaml | 20 ++++++ .../bindings/sound/nvidia,tegra210-amx.yaml | 72 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mixer.yaml | 67 ++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mvc.yaml | 79 ++++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-sfc.yaml | 76 +++++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml new file mode 100644 index 0000000..9950585 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-adx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Tegra210 ADX Device Tree Bindings
+description: |
- The Audio Demultiplexer (ADX) block takes an input stream with up to
extra spaces.
- 16 channels and demultiplexes it into four output streams of up to 16
- channels each. A byte RAM helps to form output frames by any combination
- of bytes from the input frame. Its design is identical to that of byte
- RAM in the AMX except that the data flow direction is reversed.
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^adx@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-adx
- items:
- enum:
- nvidia,tegra194-adx
- nvidia,tegra186-adx
- const: nvidia,tegra210-adx
- reg:
- maxItems: 1
- sound-name-prefix:
nvidia,sound-name-prefix
- pattern: "^ADX[1-9]$"
- $ref: /schemas/types.yaml#/definitions/string
- description:
used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "ADX1" or "ADX2" ... "ADXx", where x depends on
the maximum available instances on a Tegra SoC.
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
ADX has one input and four output. Accordingly ACIF (Audio Client
You need to define the port numbers for the input and each output.
Interface) RX and TX port nodes are defined to represent ADX inputs
and output respectively. These are connected to corresponding ports
on AHUB.
- patternProperties:
'^port@[0-9]':
Per above, this will need to be split at least into input and output ports.
Same issues in the other schemas.
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
+required:
- compatible
- reg
+additionalProperties: false
+examples:
- |
- adx@702d3800 {
compatible = "nvidia,tegra210-adx";
reg = <0x702d3800 0x100>;
sound-name-prefix = "ADX1";
- };
+... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml index 1118a94..4087eeb 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml @@ -85,6 +85,26 @@ patternProperties: type: object $ref: nvidia,tegra186-dspk.yaml#
- '^mvc@[0-9a-f]+$':
- type: object
- $ref: nvidia,tegra210-mvc.yaml#
- '^sfc@[0-9a-f]+$':
- type: object
- $ref: nvidia,tegra210-sfc.yaml#
- '^amx@[0-9a-f]+$':
- type: object
- $ref: nvidia,tegra210-amx.yaml#
- '^adx@[0-9a-f]+$':
- type: object
- $ref: nvidia,tegra210-adx.yaml#
- '^mixer@[0-9a-f]+$':
- type: object
- $ref: nvidia,tegra210-mixer.yaml#
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml new file mode 100644 index 0000000..e6b365b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-amx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Tegra210 AMX Device Tree Bindings
+description: |
- The Audio Multiplexer (AMX) block can multiplex up to four input streams
- each of which can have maximum 16 channels and generate an output stream
- with maximum 16 channels. A byte RAM helps to form an output frame by
- any combination of bytes from the input frames.
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^amx@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-amx
- items:
- const: nvidia,tegra186-amx
- const: nvidia,tegra210-amx
- const: nvidia,tegra194-amx
- reg:
- maxItems: 1
- sound-name-prefix:
- pattern: "^AMX[1-9]$"
- $ref: /schemas/types.yaml#/definitions/string
- description:
used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "AMX1" or "AMX2" ... "AMXx", where x depends on
the maximum available instances on a Tegra SoC.
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
AMX has four inputs and one output. Accordingly ACIF (Audio Client
Interfaces) RX and TX port nodes are defined to represent AMX inputs
and output respectively. These are connected to corresponding ports
on AHUB.
- patternProperties:
'^port@[0-9]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
+required:
- compatible
- reg
+additionalProperties: false
+examples:
- |
- amx@702d3000 {
compatible = "nvidia,tegra210-amx";
reg = <0x702d3000 0x100>;
sound-name-prefix = "AMX1";
- };
+... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml new file mode 100644 index 0000000..0808355 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mixer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Tegra210 Mixer Device Tree Bindings
+description: |
- The Mixer supports mixing of up to ten 7.1 audio input streams and
- generate five outputs (each of which can be any combination of the
- ten input streams).
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^mixer@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-amixer
- items:
- enum:
- nvidia,tegra194-amixer
- nvidia,tegra186-amixer
- const: nvidia,tegra210-amixer
- reg:
- maxItems: 1
- sound-name-prefix:
- const: "MIXER"
Don't need quotes. A fixed string seems a bit pointless to put into DT.
- $ref: /schemas/types.yaml#/definitions/string
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- description: |
Mixer has ten inputs and five outputs. Accordingly ACIF (Audio Client
Interfaces) RX and TX port nodes are defined to represent MIXER inputs
and outputs respectively. These are connected to corresponding ports
on AHUB.
- patternProperties:
'^port@[0-9]':
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
+required:
- compatible
- reg
+additionalProperties: false
+examples:
- |
- mixer@702dbb00 {
compatible = "nvidia,tegra210-amixer";
reg = <0x702dbb00 0x800>;
sound-name-prefix = "MIXER";
- };
+... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml new file mode 100644 index 0000000..7d81b11 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mvc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Tegra210 MVC Device Tree Bindings
+description: |
- The Master Volume Control (MVC) provides gain or attenuation to a digital
- signal path. It can be used in input or output signal path for per-stream
- volume control or it can be used as master volume control. The MVC block
- has one input and one output. The input digital stream can be mono or
- multi-channel (up to 7.1 channels) stream. An independent mute control is
- also included in the MVC block.
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^mvc@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-mvc
- items:
- enum:
- nvidia,tegra194-mvc
- nvidia,tegra186-mvc
- const: nvidia,tegra210-mvc
- reg:
- maxItems: 1
- sound-name-prefix:
- pattern: "^MVC[1-9]$"
- $ref: /schemas/types.yaml#/definitions/string
- description:
used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "MVC1" or "MVC2" ... "MVCx", where x depends on
the maximum available instances on a Tegra SoC.
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
ACIF (Audio Client Interface) acting as MVC input (RX) port.
This is connected to corresponding ACIF port on AHUB.
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
ACIF (Audio Client Interface) acting as MVC output (TX) port.
This is connected to corresponding ACIF port on AHUB.
+required:
- compatible
- reg
+additionalProperties: false
+examples:
- |
- mvc@702da000 {
compatible = "nvidia,tegra210-mvc";
reg = <0x702da000 0x200>;
sound-name-prefix = "MVC1";
- };
+... diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml new file mode 100644 index 0000000..5f05e2a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nvidia,tegra210-sfc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
+title: Tegra210 SFC Device Tree Bindings
+description: |
- The Sampling Frequency Converter (SFC) converts the sampling frequency
- of the input signal from one frequency to another. It supports sampling
- frequency conversions of streams of up to two channels (stereo).
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^sfc@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-sfc
- items:
- enum:
- nvidia,tegra194-sfc
- nvidia,tegra186-sfc
- const: nvidia,tegra210-sfc
- reg:
- maxItems: 1
- sound-name-prefix:
- pattern: "^SFC[1-9]$"
- $ref: /schemas/types.yaml#/definitions/string
- description:
used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
The name can be "SFC1" or "SFC2" ... "SFCx", where x depends on
the maximum available instances on a Tegra SoC.
- ports:
- $ref: /schemas/graph.yaml#/properties/ports
- properties:
port@0:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
ACIF (Audio Client Interface) acting as SFC input (RX) port.
This is connected to corresponding ACIF port on AHUB.
port@1:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: |
ACIF (Audio Client Interface) acting as SFC output (TX) port.
This is connected to corresponding ACIF port on AHUB.
+required:
- compatible
- reg
+additionalProperties: false
+examples:
- |
- sfc@702d2000 {
compatible = "nvidia,tegra210-sfc";
reg = <0x702d2000 0x200>;
sound-name-prefix = "SFC1";
- };
+...
2.7.4
Hi Rob,
Thanks for feedback.
On 9/1/2021 1:51 AM, Rob Herring wrote:
On Fri, Aug 27, 2021 at 03:03:50PM +0530, Sameer Pujar wrote:
This patch adds YAML schema for DT bindings of few AHUB modules. These devices will be registered as ASoC components and bindings will be used on Tegra210 and later chips. The bindings for below mentioned modules are added:
- SFC (Sampling Frequency Converter)
- MVC (Master Volume Control)
- AMX (Audio Multiplexer)
- ADX (Audio Demultiplexer)
- Mixer
Signed-off-by: Sameer Pujar spujar@nvidia.com Cc: Rob Herring robh+dt@kernel.org
.../bindings/sound/nvidia,tegra210-adx.yaml | 74 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-ahub.yaml | 20 ++++++ .../bindings/sound/nvidia,tegra210-amx.yaml | 72 ++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mixer.yaml | 67 ++++++++++++++++++ .../bindings/sound/nvidia,tegra210-mvc.yaml | 79 ++++++++++++++++++++++ .../bindings/sound/nvidia,tegra210-sfc.yaml | 76 +++++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-adx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-amx.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mixer.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-mvc.yaml create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra210-sfc.yaml
[...]
- 16 channels and demultiplexes it into four output streams of up to 16
- channels each. A byte RAM helps to form output frames by any combination
- of bytes from the input frame. Its design is identical to that of byte
- RAM in the AMX except that the data flow direction is reversed.
+maintainers:
- Jon Hunter jonathanh@nvidia.com
- Mohan Kumar mkumard@nvidia.com
- Sameer Pujar spujar@nvidia.com
+properties:
- $nodename:
- pattern: "^adx@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra210-adx
- items:
- enum:
- nvidia,tegra194-adx
- nvidia,tegra186-adx
- const: nvidia,tegra210-adx
- reg:
- maxItems: 1
- sound-name-prefix:
nvidia,sound-name-prefix
It is supposed to be 'sound-name-prefix' for core to parse and apply prefix. May be this needs to be directly referenced from 'Documentation/devicetree/bindings/sound/name-prefix.txt' after converting to YAML, which can be a separate commit?
Remaining comments will be taken care in next revision.
Add routing support for following modules of AHUB: * SFC (Sampling Frequency Converter) * MVC (Master Volume Control) * AMX (Audio Multiplexer) * ADX (Audio Demultiplexer) * Mixer
These modules can be plugged into audio path as per the need using routing controls similar to the already existing routes to I/O modules such as I2S, DMIC and DSPK.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/tegra210_ahub.c | 511 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 509 insertions(+), 2 deletions(-)
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 66287a7..44a1ee0 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -105,14 +105,68 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = { DAI(ADMAIF8), DAI(ADMAIF9), DAI(ADMAIF10), + /* XBAR <-> I2S <-> Codec */ DAI(I2S1), DAI(I2S2), DAI(I2S3), DAI(I2S4), DAI(I2S5), + /* XBAR <- DMIC <- Codec */ DAI(DMIC1), DAI(DMIC2), DAI(DMIC3), + /* XBAR -> SFC -> XBAR */ + DAI(SFC1 RX), + DAI(SFC1 TX), + DAI(SFC2 RX), + DAI(SFC2 TX), + DAI(SFC3 RX), + DAI(SFC3 TX), + DAI(SFC4 RX), + DAI(SFC4 TX), + /* XBAR -> MVC -> XBAR */ + DAI(MVC1 RX), + DAI(MVC1 TX), + DAI(MVC2 RX), + DAI(MVC2 TX), + /* XBAR -> AMX(4:1) -> XBAR */ + DAI(AMX1 RX1), + DAI(AMX1 RX2), + DAI(AMX1 RX3), + DAI(AMX1 RX4), + DAI(AMX1), + DAI(AMX2 RX1), + DAI(AMX2 RX2), + DAI(AMX2 RX3), + DAI(AMX2 RX4), + DAI(AMX2), + /* XBAR -> ADX(1:4) -> XBAR */ + DAI(ADX1), + DAI(ADX1 TX1), + DAI(ADX1 TX2), + DAI(ADX1 TX3), + DAI(ADX1 TX4), + DAI(ADX2), + DAI(ADX2 TX1), + DAI(ADX2 TX2), + DAI(ADX2 TX3), + DAI(ADX2 TX4), + /* XBAR -> MIXER(10:5) -> XBAR */ + DAI(MIXER RX1), + DAI(MIXER RX2), + DAI(MIXER RX3), + DAI(MIXER RX4), + DAI(MIXER RX5), + DAI(MIXER RX6), + DAI(MIXER RX7), + DAI(MIXER RX8), + DAI(MIXER RX9), + DAI(MIXER RX10), + DAI(MIXER TX1), + DAI(MIXER TX2), + DAI(MIXER TX3), + DAI(MIXER TX4), + DAI(MIXER TX5), };
static struct snd_soc_dai_driver tegra186_ahub_dais[] = { @@ -136,18 +190,93 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = { DAI(ADMAIF18), DAI(ADMAIF19), DAI(ADMAIF20), + /* XBAR <-> I2S <-> Codec */ DAI(I2S1), DAI(I2S2), DAI(I2S3), DAI(I2S4), DAI(I2S5), DAI(I2S6), + /* XBAR <- DMIC <- Codec */ DAI(DMIC1), DAI(DMIC2), DAI(DMIC3), DAI(DMIC4), + /* XBAR -> DSPK -> Codec */ DAI(DSPK1), DAI(DSPK2), + /* XBAR -> SFC -> XBAR */ + DAI(SFC1 RX), + DAI(SFC1 TX), + DAI(SFC2 RX), + DAI(SFC2 TX), + DAI(SFC3 RX), + DAI(SFC3 TX), + DAI(SFC4 RX), + DAI(SFC4 TX), + /* XBAR -> MVC -> XBAR */ + DAI(MVC1 RX), + DAI(MVC1 TX), + DAI(MVC2 RX), + DAI(MVC2 TX), + /* XBAR -> AMX(4:1) -> XBAR */ + DAI(AMX1 RX1), + DAI(AMX1 RX2), + DAI(AMX1 RX3), + DAI(AMX1 RX4), + DAI(AMX1), + DAI(AMX2 RX1), + DAI(AMX2 RX2), + DAI(AMX2 RX3), + DAI(AMX2 RX4), + DAI(AMX2), + DAI(AMX3 RX1), + DAI(AMX3 RX2), + DAI(AMX3 RX3), + DAI(AMX3 RX4), + DAI(AMX3), + DAI(AMX4 RX1), + DAI(AMX4 RX2), + DAI(AMX4 RX3), + DAI(AMX4 RX4), + DAI(AMX4), + /* XBAR -> ADX(1:4) -> XBAR */ + DAI(ADX1), + DAI(ADX1 TX1), + DAI(ADX1 TX2), + DAI(ADX1 TX3), + DAI(ADX1 TX4), + DAI(ADX2), + DAI(ADX2 TX1), + DAI(ADX2 TX2), + DAI(ADX2 TX3), + DAI(ADX2 TX4), + DAI(ADX3), + DAI(ADX3 TX1), + DAI(ADX3 TX2), + DAI(ADX3 TX3), + DAI(ADX3 TX4), + DAI(ADX4), + DAI(ADX4 TX1), + DAI(ADX4 TX2), + DAI(ADX4 TX3), + DAI(ADX4 TX4), + /* XBAR -> MIXER(10:5) -> XBAR */ + DAI(MIXER RX1), + DAI(MIXER RX2), + DAI(MIXER RX3), + DAI(MIXER RX4), + DAI(MIXER RX5), + DAI(MIXER RX6), + DAI(MIXER RX7), + DAI(MIXER RX8), + DAI(MIXER RX9), + DAI(MIXER RX10), + DAI(MIXER TX1), + DAI(MIXER TX2), + DAI(MIXER TX3), + DAI(MIXER TX4), + DAI(MIXER TX5), };
static const char * const tegra210_ahub_mux_texts[] = { @@ -170,6 +299,27 @@ static const char * const tegra210_ahub_mux_texts[] = { "DMIC1", "DMIC2", "DMIC3", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MVC1", + "MVC2", + "AMX1", + "AMX2", + "ADX1 TX1", + "ADX1 TX2", + "ADX1 TX3", + "ADX1 TX4", + "ADX2 TX1", + "ADX2 TX2", + "ADX2 TX3", + "ADX2 TX4", + "MIXER TX1", + "MIXER TX2", + "MIXER TX3", + "MIXER TX4", + "MIXER TX5", };
static const char * const tegra186_ahub_mux_texts[] = { @@ -204,10 +354,42 @@ static const char * const tegra186_ahub_mux_texts[] = { "DMIC2", "DMIC3", "DMIC4", + "SFC1", + "SFC2", + "SFC3", + "SFC4", + "MVC1", + "MVC2", + "AMX1", + "AMX2", + "AMX3", + "AMX4", + "ADX1 TX1", + "ADX1 TX2", + "ADX1 TX3", + "ADX1 TX4", + "ADX2 TX1", + "ADX2 TX2", + "ADX2 TX3", + "ADX2 TX4", + "ADX3 TX1", + "ADX3 TX2", + "ADX3 TX3", + "ADX3 TX4", + "ADX4 TX1", + "ADX4 TX2", + "ADX4 TX3", + "ADX4 TX4", + "MIXER TX1", + "MIXER TX2", + "MIXER TX3", + "MIXER TX4", + "MIXER TX5", };
static const unsigned int tegra210_ahub_mux_values[] = { 0, + /* ADMAIF */ MUX_VALUE(0, 0), MUX_VALUE(0, 1), MUX_VALUE(0, 2), @@ -218,18 +400,47 @@ static const unsigned int tegra210_ahub_mux_values[] = { MUX_VALUE(0, 7), MUX_VALUE(0, 8), MUX_VALUE(0, 9), + /* I2S */ MUX_VALUE(0, 16), MUX_VALUE(0, 17), MUX_VALUE(0, 18), MUX_VALUE(0, 19), MUX_VALUE(0, 20), + /* DMIC */ MUX_VALUE(2, 18), MUX_VALUE(2, 19), MUX_VALUE(2, 20), + /* SFC */ + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + /* MVC */ + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + /* AMX */ + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + /* ADX */ + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + /* MIXER */ + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), };
static const unsigned int tegra186_ahub_mux_values[] = { 0, + /* ADMAIF */ MUX_VALUE(0, 0), MUX_VALUE(0, 1), MUX_VALUE(0, 2), @@ -246,20 +457,59 @@ static const unsigned int tegra186_ahub_mux_values[] = { MUX_VALUE(0, 13), MUX_VALUE(0, 14), MUX_VALUE(0, 15), + /* I2S */ MUX_VALUE(0, 16), MUX_VALUE(0, 17), MUX_VALUE(0, 18), MUX_VALUE(0, 19), MUX_VALUE(0, 20), MUX_VALUE(0, 21), + /* ADMAIF */ MUX_VALUE(3, 16), MUX_VALUE(3, 17), MUX_VALUE(3, 18), MUX_VALUE(3, 19), + /* DMIC */ MUX_VALUE(2, 18), MUX_VALUE(2, 19), MUX_VALUE(2, 20), MUX_VALUE(2, 21), + /* SFC */ + MUX_VALUE(0, 24), + MUX_VALUE(0, 25), + MUX_VALUE(0, 26), + MUX_VALUE(0, 27), + /* MVC */ + MUX_VALUE(2, 8), + MUX_VALUE(2, 9), + /* AMX */ + MUX_VALUE(1, 8), + MUX_VALUE(1, 9), + MUX_VALUE(1, 10), + MUX_VALUE(1, 11), + /* ADX */ + MUX_VALUE(2, 24), + MUX_VALUE(2, 25), + MUX_VALUE(2, 26), + MUX_VALUE(2, 27), + MUX_VALUE(2, 28), + MUX_VALUE(2, 29), + MUX_VALUE(2, 30), + MUX_VALUE(2, 31), + MUX_VALUE(3, 0), + MUX_VALUE(3, 1), + MUX_VALUE(3, 2), + MUX_VALUE(3, 3), + MUX_VALUE(3, 4), + MUX_VALUE(3, 5), + MUX_VALUE(3, 6), + MUX_VALUE(3, 7), + /* MIXER */ + MUX_VALUE(1, 0), + MUX_VALUE(1, 1), + MUX_VALUE(1, 2), + MUX_VALUE(1, 3), + MUX_VALUE(1, 4), };
/* Controls for t210 */ @@ -278,6 +528,32 @@ MUX_ENUM_CTRL_DECL(t210_i2s2_tx, 0x11); MUX_ENUM_CTRL_DECL(t210_i2s3_tx, 0x12); MUX_ENUM_CTRL_DECL(t210_i2s4_tx, 0x13); MUX_ENUM_CTRL_DECL(t210_i2s5_tx, 0x14); +MUX_ENUM_CTRL_DECL(t210_sfc1_tx, 0x18); +MUX_ENUM_CTRL_DECL(t210_sfc2_tx, 0x19); +MUX_ENUM_CTRL_DECL(t210_sfc3_tx, 0x1a); +MUX_ENUM_CTRL_DECL(t210_sfc4_tx, 0x1b); +MUX_ENUM_CTRL_DECL(t210_mvc1_tx, 0x48); +MUX_ENUM_CTRL_DECL(t210_mvc2_tx, 0x49); +MUX_ENUM_CTRL_DECL(t210_amx11_tx, 0x50); +MUX_ENUM_CTRL_DECL(t210_amx12_tx, 0x51); +MUX_ENUM_CTRL_DECL(t210_amx13_tx, 0x52); +MUX_ENUM_CTRL_DECL(t210_amx14_tx, 0x53); +MUX_ENUM_CTRL_DECL(t210_amx21_tx, 0x54); +MUX_ENUM_CTRL_DECL(t210_amx22_tx, 0x55); +MUX_ENUM_CTRL_DECL(t210_amx23_tx, 0x56); +MUX_ENUM_CTRL_DECL(t210_amx24_tx, 0x57); +MUX_ENUM_CTRL_DECL(t210_adx1_tx, 0x58); +MUX_ENUM_CTRL_DECL(t210_adx2_tx, 0x59); +MUX_ENUM_CTRL_DECL(t210_mixer11_tx, 0x20); +MUX_ENUM_CTRL_DECL(t210_mixer12_tx, 0x21); +MUX_ENUM_CTRL_DECL(t210_mixer13_tx, 0x22); +MUX_ENUM_CTRL_DECL(t210_mixer14_tx, 0x23); +MUX_ENUM_CTRL_DECL(t210_mixer15_tx, 0x24); +MUX_ENUM_CTRL_DECL(t210_mixer16_tx, 0x25); +MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26); +MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27); +MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28); +MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
/* Controls for t186 */ MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00); @@ -308,6 +584,42 @@ MUX_ENUM_CTRL_DECL_186(t186_admaif17_tx, 0x68); MUX_ENUM_CTRL_DECL_186(t186_admaif18_tx, 0x69); MUX_ENUM_CTRL_DECL_186(t186_admaif19_tx, 0x6a); MUX_ENUM_CTRL_DECL_186(t186_admaif20_tx, 0x6b); +MUX_ENUM_CTRL_DECL_186(t186_sfc1_tx, 0x18); +MUX_ENUM_CTRL_DECL_186(t186_sfc2_tx, 0x19); +MUX_ENUM_CTRL_DECL_186(t186_sfc3_tx, 0x1a); +MUX_ENUM_CTRL_DECL_186(t186_sfc4_tx, 0x1b); +MUX_ENUM_CTRL_DECL_186(t186_mvc1_tx, 0x48); +MUX_ENUM_CTRL_DECL_186(t186_mvc2_tx, 0x49); +MUX_ENUM_CTRL_DECL_186(t186_amx11_tx, 0x50); +MUX_ENUM_CTRL_DECL_186(t186_amx12_tx, 0x51); +MUX_ENUM_CTRL_DECL_186(t186_amx13_tx, 0x52); +MUX_ENUM_CTRL_DECL_186(t186_amx14_tx, 0x53); +MUX_ENUM_CTRL_DECL_186(t186_amx21_tx, 0x54); +MUX_ENUM_CTRL_DECL_186(t186_amx22_tx, 0x55); +MUX_ENUM_CTRL_DECL_186(t186_amx23_tx, 0x56); +MUX_ENUM_CTRL_DECL_186(t186_amx24_tx, 0x57); +MUX_ENUM_CTRL_DECL_186(t186_amx31_tx, 0x58); +MUX_ENUM_CTRL_DECL_186(t186_amx32_tx, 0x59); +MUX_ENUM_CTRL_DECL_186(t186_amx33_tx, 0x5a); +MUX_ENUM_CTRL_DECL_186(t186_amx34_tx, 0x5b); +MUX_ENUM_CTRL_DECL_186(t186_amx41_tx, 0x64); +MUX_ENUM_CTRL_DECL_186(t186_amx42_tx, 0x65); +MUX_ENUM_CTRL_DECL_186(t186_amx43_tx, 0x66); +MUX_ENUM_CTRL_DECL_186(t186_amx44_tx, 0x67); +MUX_ENUM_CTRL_DECL_186(t186_adx1_tx, 0x60); +MUX_ENUM_CTRL_DECL_186(t186_adx2_tx, 0x61); +MUX_ENUM_CTRL_DECL_186(t186_adx3_tx, 0x62); +MUX_ENUM_CTRL_DECL_186(t186_adx4_tx, 0x63); +MUX_ENUM_CTRL_DECL_186(t186_mixer11_tx, 0x20); +MUX_ENUM_CTRL_DECL_186(t186_mixer12_tx, 0x21); +MUX_ENUM_CTRL_DECL_186(t186_mixer13_tx, 0x22); +MUX_ENUM_CTRL_DECL_186(t186_mixer14_tx, 0x23); +MUX_ENUM_CTRL_DECL_186(t186_mixer15_tx, 0x24); +MUX_ENUM_CTRL_DECL_186(t186_mixer16_tx, 0x25); +MUX_ENUM_CTRL_DECL_186(t186_mixer17_tx, 0x26); +MUX_ENUM_CTRL_DECL_186(t186_mixer18_tx, 0x27); +MUX_ENUM_CTRL_DECL_186(t186_mixer19_tx, 0x28); +MUX_ENUM_CTRL_DECL_186(t186_mixer110_tx, 0x29);
/* * The number of entries in, and order of, this array is closely tied to the @@ -333,6 +645,47 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = { TX_WIDGETS("DMIC1"), TX_WIDGETS("DMIC2"), TX_WIDGETS("DMIC3"), + WIDGETS("SFC1", t210_sfc1_tx), + WIDGETS("SFC2", t210_sfc2_tx), + WIDGETS("SFC3", t210_sfc3_tx), + WIDGETS("SFC4", t210_sfc4_tx), + WIDGETS("MVC1", t210_mvc1_tx), + WIDGETS("MVC2", t210_mvc2_tx), + WIDGETS("AMX1 RX1", t210_amx11_tx), + WIDGETS("AMX1 RX2", t210_amx12_tx), + WIDGETS("AMX1 RX3", t210_amx13_tx), + WIDGETS("AMX1 RX4", t210_amx14_tx), + WIDGETS("AMX2 RX1", t210_amx21_tx), + WIDGETS("AMX2 RX2", t210_amx22_tx), + WIDGETS("AMX2 RX3", t210_amx23_tx), + WIDGETS("AMX2 RX4", t210_amx24_tx), + TX_WIDGETS("AMX1"), + TX_WIDGETS("AMX2"), + WIDGETS("ADX1", t210_adx1_tx), + WIDGETS("ADX2", t210_adx2_tx), + TX_WIDGETS("ADX1 TX1"), + TX_WIDGETS("ADX1 TX2"), + TX_WIDGETS("ADX1 TX3"), + TX_WIDGETS("ADX1 TX4"), + TX_WIDGETS("ADX2 TX1"), + TX_WIDGETS("ADX2 TX2"), + TX_WIDGETS("ADX2 TX3"), + TX_WIDGETS("ADX2 TX4"), + WIDGETS("MIXER RX1", t210_mixer11_tx), + WIDGETS("MIXER RX2", t210_mixer12_tx), + WIDGETS("MIXER RX3", t210_mixer13_tx), + WIDGETS("MIXER RX4", t210_mixer14_tx), + WIDGETS("MIXER RX5", t210_mixer15_tx), + WIDGETS("MIXER RX6", t210_mixer16_tx), + WIDGETS("MIXER RX7", t210_mixer17_tx), + WIDGETS("MIXER RX8", t210_mixer18_tx), + WIDGETS("MIXER RX9", t210_mixer19_tx), + WIDGETS("MIXER RX10", t210_mixer110_tx), + TX_WIDGETS("MIXER TX1"), + TX_WIDGETS("MIXER TX2"), + TX_WIDGETS("MIXER TX3"), + TX_WIDGETS("MIXER TX4"), + TX_WIDGETS("MIXER TX5"), };
static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { @@ -368,6 +721,67 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { TX_WIDGETS("DMIC4"), WIDGETS("DSPK1", t186_dspk1_tx), WIDGETS("DSPK2", t186_dspk2_tx), + WIDGETS("SFC1", t186_sfc1_tx), + WIDGETS("SFC2", t186_sfc2_tx), + WIDGETS("SFC3", t186_sfc3_tx), + WIDGETS("SFC4", t186_sfc4_tx), + WIDGETS("MVC1", t186_mvc1_tx), + WIDGETS("MVC2", t186_mvc2_tx), + WIDGETS("AMX1 RX1", t186_amx11_tx), + WIDGETS("AMX1 RX2", t186_amx12_tx), + WIDGETS("AMX1 RX3", t186_amx13_tx), + WIDGETS("AMX1 RX4", t186_amx14_tx), + WIDGETS("AMX2 RX1", t186_amx21_tx), + WIDGETS("AMX2 RX2", t186_amx22_tx), + WIDGETS("AMX2 RX3", t186_amx23_tx), + WIDGETS("AMX2 RX4", t186_amx24_tx), + WIDGETS("AMX3 RX1", t186_amx31_tx), + WIDGETS("AMX3 RX2", t186_amx32_tx), + WIDGETS("AMX3 RX3", t186_amx33_tx), + WIDGETS("AMX3 RX4", t186_amx34_tx), + WIDGETS("AMX4 RX1", t186_amx41_tx), + WIDGETS("AMX4 RX2", t186_amx42_tx), + WIDGETS("AMX4 RX3", t186_amx43_tx), + WIDGETS("AMX4 RX4", t186_amx44_tx), + TX_WIDGETS("AMX1"), + TX_WIDGETS("AMX2"), + TX_WIDGETS("AMX3"), + TX_WIDGETS("AMX4"), + WIDGETS("ADX1", t186_adx1_tx), + WIDGETS("ADX2", t186_adx2_tx), + WIDGETS("ADX3", t186_adx3_tx), + WIDGETS("ADX4", t186_adx4_tx), + TX_WIDGETS("ADX1 TX1"), + TX_WIDGETS("ADX1 TX2"), + TX_WIDGETS("ADX1 TX3"), + TX_WIDGETS("ADX1 TX4"), + TX_WIDGETS("ADX2 TX1"), + TX_WIDGETS("ADX2 TX2"), + TX_WIDGETS("ADX2 TX3"), + TX_WIDGETS("ADX2 TX4"), + TX_WIDGETS("ADX3 TX1"), + TX_WIDGETS("ADX3 TX2"), + TX_WIDGETS("ADX3 TX3"), + TX_WIDGETS("ADX3 TX4"), + TX_WIDGETS("ADX4 TX1"), + TX_WIDGETS("ADX4 TX2"), + TX_WIDGETS("ADX4 TX3"), + TX_WIDGETS("ADX4 TX4"), + WIDGETS("MIXER RX1", t186_mixer11_tx), + WIDGETS("MIXER RX2", t186_mixer12_tx), + WIDGETS("MIXER RX3", t186_mixer13_tx), + WIDGETS("MIXER RX4", t186_mixer14_tx), + WIDGETS("MIXER RX5", t186_mixer15_tx), + WIDGETS("MIXER RX6", t186_mixer16_tx), + WIDGETS("MIXER RX7", t186_mixer17_tx), + WIDGETS("MIXER RX8", t186_mixer18_tx), + WIDGETS("MIXER RX9", t186_mixer19_tx), + WIDGETS("MIXER RX10", t186_mixer110_tx), + TX_WIDGETS("MIXER TX1"), + TX_WIDGETS("MIXER TX2"), + TX_WIDGETS("MIXER TX3"), + TX_WIDGETS("MIXER TX4"), + TX_WIDGETS("MIXER TX5"), };
#define TEGRA_COMMON_MUX_ROUTES(name) \ @@ -389,7 +803,28 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { { name " Mux", "I2S5", "I2S5 XBAR-RX" }, \ { name " Mux", "DMIC1", "DMIC1 XBAR-RX" }, \ { name " Mux", "DMIC2", "DMIC2 XBAR-RX" }, \ - { name " Mux", "DMIC3", "DMIC3 XBAR-RX" }, + { name " Mux", "DMIC3", "DMIC3 XBAR-RX" }, \ + { name " Mux", "SFC1", "SFC1 XBAR-RX" }, \ + { name " Mux", "SFC2", "SFC2 XBAR-RX" }, \ + { name " Mux", "SFC3", "SFC3 XBAR-RX" }, \ + { name " Mux", "SFC4", "SFC4 XBAR-RX" }, \ + { name " Mux", "MVC1", "MVC1 XBAR-RX" }, \ + { name " Mux", "MVC2", "MVC2 XBAR-RX" }, \ + { name " Mux", "AMX1", "AMX1 XBAR-RX" }, \ + { name " Mux", "AMX2", "AMX2 XBAR-RX" }, \ + { name " Mux", "ADX1 TX1", "ADX1 TX1 XBAR-RX" }, \ + { name " Mux", "ADX1 TX2", "ADX1 TX2 XBAR-RX" }, \ + { name " Mux", "ADX1 TX3", "ADX1 TX3 XBAR-RX" }, \ + { name " Mux", "ADX1 TX4", "ADX1 TX4 XBAR-RX" }, \ + { name " Mux", "ADX2 TX1", "ADX2 TX1 XBAR-RX" }, \ + { name " Mux", "ADX2 TX2", "ADX2 TX2 XBAR-RX" }, \ + { name " Mux", "ADX2 TX3", "ADX2 TX3 XBAR-RX" }, \ + { name " Mux", "ADX2 TX4", "ADX2 TX4 XBAR-RX" }, \ + { name " Mux", "MIXER TX1", "MIXER TX1 XBAR-RX" }, \ + { name " Mux", "MIXER TX2", "MIXER TX2 XBAR-RX" }, \ + { name " Mux", "MIXER TX3", "MIXER TX3 XBAR-RX" }, \ + { name " Mux", "MIXER TX4", "MIXER TX4 XBAR-RX" }, \ + { name " Mux", "MIXER TX5", "MIXER TX5 XBAR-RX" },
#define TEGRA186_ONLY_MUX_ROUTES(name) \ { name " Mux", "ADMAIF11", "ADMAIF11 XBAR-RX" }, \ @@ -403,7 +838,17 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = { { name " Mux", "ADMAIF19", "ADMAIF19 XBAR-RX" }, \ { name " Mux", "ADMAIF20", "ADMAIF20 XBAR-RX" }, \ { name " Mux", "I2S6", "I2S6 XBAR-RX" }, \ - { name " Mux", "DMIC4", "DMIC4 XBAR-RX" }, + { name " Mux", "DMIC4", "DMIC4 XBAR-RX" }, \ + { name " Mux", "AMX3", "AMX3 XBAR-RX" }, \ + { name " Mux", "AMX4", "AMX4 XBAR-RX" }, \ + { name " Mux", "ADX3 TX1", "ADX3 TX1 XBAR-RX" }, \ + { name " Mux", "ADX3 TX2", "ADX3 TX2 XBAR-RX" }, \ + { name " Mux", "ADX3 TX3", "ADX3 TX3 XBAR-RX" }, \ + { name " Mux", "ADX3 TX4", "ADX3 TX4 XBAR-RX" }, \ + { name " Mux", "ADX4 TX1", "ADX4 TX1 XBAR-RX" }, \ + { name " Mux", "ADX4 TX2", "ADX4 TX2 XBAR-RX" }, \ + { name " Mux", "ADX4 TX3", "ADX4 TX3 XBAR-RX" }, \ + { name " Mux", "ADX4 TX4", "ADX4 TX4 XBAR-RX" },
#define TEGRA210_MUX_ROUTES(name) \ TEGRA_COMMON_MUX_ROUTES(name) @@ -450,6 +895,32 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = { TEGRA210_MUX_ROUTES("I2S3") TEGRA210_MUX_ROUTES("I2S4") TEGRA210_MUX_ROUTES("I2S5") + TEGRA210_MUX_ROUTES("SFC1") + TEGRA210_MUX_ROUTES("SFC2") + TEGRA210_MUX_ROUTES("SFC3") + TEGRA210_MUX_ROUTES("SFC4") + TEGRA210_MUX_ROUTES("MVC1") + TEGRA210_MUX_ROUTES("MVC2") + TEGRA210_MUX_ROUTES("AMX1 RX1") + TEGRA210_MUX_ROUTES("AMX1 RX2") + TEGRA210_MUX_ROUTES("AMX1 RX3") + TEGRA210_MUX_ROUTES("AMX1 RX4") + TEGRA210_MUX_ROUTES("AMX2 RX1") + TEGRA210_MUX_ROUTES("AMX2 RX2") + TEGRA210_MUX_ROUTES("AMX2 RX3") + TEGRA210_MUX_ROUTES("AMX2 RX4") + TEGRA210_MUX_ROUTES("ADX1") + TEGRA210_MUX_ROUTES("ADX2") + TEGRA210_MUX_ROUTES("MIXER RX1") + TEGRA210_MUX_ROUTES("MIXER RX2") + TEGRA210_MUX_ROUTES("MIXER RX3") + TEGRA210_MUX_ROUTES("MIXER RX4") + TEGRA210_MUX_ROUTES("MIXER RX5") + TEGRA210_MUX_ROUTES("MIXER RX6") + TEGRA210_MUX_ROUTES("MIXER RX7") + TEGRA210_MUX_ROUTES("MIXER RX8") + TEGRA210_MUX_ROUTES("MIXER RX9") + TEGRA210_MUX_ROUTES("MIXER RX10") };
static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { @@ -501,6 +972,42 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = { TEGRA186_MUX_ROUTES("I2S6") TEGRA186_MUX_ROUTES("DSPK1") TEGRA186_MUX_ROUTES("DSPK2") + TEGRA186_MUX_ROUTES("SFC1") + TEGRA186_MUX_ROUTES("SFC2") + TEGRA186_MUX_ROUTES("SFC3") + TEGRA186_MUX_ROUTES("SFC4") + TEGRA186_MUX_ROUTES("MVC1") + TEGRA186_MUX_ROUTES("MVC2") + TEGRA186_MUX_ROUTES("AMX1 RX1") + TEGRA186_MUX_ROUTES("AMX1 RX2") + TEGRA186_MUX_ROUTES("AMX1 RX3") + TEGRA186_MUX_ROUTES("AMX1 RX4") + TEGRA186_MUX_ROUTES("AMX2 RX1") + TEGRA186_MUX_ROUTES("AMX2 RX2") + TEGRA186_MUX_ROUTES("AMX2 RX3") + TEGRA186_MUX_ROUTES("AMX2 RX4") + TEGRA186_MUX_ROUTES("AMX3 RX1") + TEGRA186_MUX_ROUTES("AMX3 RX2") + TEGRA186_MUX_ROUTES("AMX3 RX3") + TEGRA186_MUX_ROUTES("AMX3 RX4") + TEGRA186_MUX_ROUTES("AMX4 RX1") + TEGRA186_MUX_ROUTES("AMX4 RX2") + TEGRA186_MUX_ROUTES("AMX4 RX3") + TEGRA186_MUX_ROUTES("AMX4 RX4") + TEGRA186_MUX_ROUTES("ADX1") + TEGRA186_MUX_ROUTES("ADX2") + TEGRA186_MUX_ROUTES("ADX3") + TEGRA186_MUX_ROUTES("ADX4") + TEGRA186_MUX_ROUTES("MIXER RX1") + TEGRA186_MUX_ROUTES("MIXER RX2") + TEGRA186_MUX_ROUTES("MIXER RX3") + TEGRA186_MUX_ROUTES("MIXER RX4") + TEGRA186_MUX_ROUTES("MIXER RX5") + TEGRA186_MUX_ROUTES("MIXER RX6") + TEGRA186_MUX_ROUTES("MIXER RX7") + TEGRA186_MUX_ROUTES("MIXER RX8") + TEGRA186_MUX_ROUTES("MIXER RX9") + TEGRA186_MUX_ROUTES("MIXER RX10") };
static const struct snd_soc_component_driver tegra210_ahub_component = {
The Master Volume Control (MVC) provides gain or attenuation to a digital signal path. It can be used in input or output signal path for per-stream volume control or it can be used as master volume control. The MVC block has one input and one output. The input digital stream can be mono or multi-channel (up to 7.1 channels) stream. An independent mute control is also included in the MVC block.
This patch registers MVC driver with ASoC framework. The component driver exposes DAPM widgets, routes and kcontrols for the device. The DAI driver exposes MVC interfaces, which can be used to connect different components in the ASoC layer. Makefile and Kconfig support is added to allow build the driver. It can be enabled in the DT via "nvidia,tegra210-mvc" compatible binding.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/Kconfig | 9 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra210_mvc.c | 629 +++++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra210_mvc.h | 117 ++++++++ 4 files changed, 757 insertions(+) create mode 100644 sound/soc/tegra/tegra210_mvc.c create mode 100644 sound/soc/tegra/tegra210_mvc.h
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 83c87f3..b8825e9 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -108,6 +108,15 @@ config SND_SOC_TEGRA210_ADMAIF channel. Buffer size is configurable for each ADMAIIF channel. Say Y or M if you want to add support for Tegra210 ADMAIF module.
+config SND_SOC_TEGRA210_MVC + tristate "Tegra210 MVC module" + help + Config to enable the digital Master Volume Controller (MVC) which + provides gain or attenuation to a digital signal path. It can be + used in input or output signal path. It can be used either for + per-stream volume control or for master volume control. + Say Y or M if you want to add support for Tegra210 MVC module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index e2cec9a..b58d041 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -13,6 +13,7 @@ snd-soc-tegra210-dmic-objs := tegra210_dmic.o snd-soc-tegra210-i2s-objs := tegra210_i2s.o snd-soc-tegra186-dspk-objs := tegra186_dspk.o snd-soc-tegra210-admaif-objs := tegra210_admaif.o +snd-soc-tegra210-mvc-objs := tegra210_mvc.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -26,6 +27,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_AHUB) += snd-soc-tegra210-ahub.o obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o +obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o
# Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c new file mode 100644 index 0000000..4942813 --- /dev/null +++ b/sound/soc/tegra/tegra210_mvc.c @@ -0,0 +1,629 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_mvc.c - Tegra210 MVC driver +// +// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_mvc.h" +#include "tegra_cif.h" + +static const struct reg_default tegra210_mvc_reg_defaults[] = { + { TEGRA210_MVC_RX_INT_MASK, 0x00000001}, + { TEGRA210_MVC_RX_CIF_CTRL, 0x00007700}, + { TEGRA210_MVC_TX_INT_MASK, 0x00000001}, + { TEGRA210_MVC_TX_CIF_CTRL, 0x00007700}, + { TEGRA210_MVC_CG, 0x1}, + { TEGRA210_MVC_CTRL, TEGRA210_MVC_CTRL_DEFAULT}, + { TEGRA210_MVC_INIT_VOL, 0x00800000}, + { TEGRA210_MVC_TARGET_VOL, 0x00800000}, + { TEGRA210_MVC_DURATION, 0x000012c0}, + { TEGRA210_MVC_DURATION_INV, 0x0006d3a0}, + { TEGRA210_MVC_POLY_N1, 0x0000007d}, + { TEGRA210_MVC_POLY_N2, 0x00000271}, + { TEGRA210_MVC_PEAK_CTRL, 0x000012c0}, + { TEGRA210_MVC_CFG_RAM_CTRL, 0x00004000}, +}; + +static const struct tegra210_mvc_gain_params gain_params = { + .poly_coeff = { 23738319, 659403, -3680, + 15546680, 2530732, -120985, + 12048422, 5527252, -785042 }, + .poly_n1 = 16, + .poly_n2 = 63, + .duration = 150, + .duration_inv = 14316558, +}; + +static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev) +{ + struct tegra210_mvc *mvc = dev_get_drvdata(dev); + + regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &(mvc->ctrl_value)); + + regcache_cache_only(mvc->regmap, true); + regcache_mark_dirty(mvc->regmap); + + return 0; +} + +static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev) +{ + struct tegra210_mvc *mvc = dev_get_drvdata(dev); + + regcache_cache_only(mvc->regmap, false); + regcache_sync(mvc->regmap); + + regmap_write(mvc->regmap, TEGRA210_MVC_CTRL, mvc->ctrl_value); + regmap_update_bits(mvc->regmap, + TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + + return 0; +} + +static int tegra210_mvc_write_ram(struct tegra210_mvc *mvc, + unsigned int addr, unsigned int coef) +{ + unsigned int reg, val; + int err; + + err = regmap_read_poll_timeout(mvc->regmap, + TEGRA210_MVC_CFG_RAM_CTRL, + val, !(val & 0x80000000), 10, 10000); + if (err < 0) + return err; + + reg = (addr << TEGRA210_MVC_CFG_RAM_CTRL_ADDR_SHIFT) & + TEGRA210_MVC_CFG_RAM_CTRL_ADDR_MASK; + reg |= TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN; + reg |= TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE; + reg |= TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN; + + regmap_write(mvc->regmap, TEGRA210_MVC_CFG_RAM_CTRL, reg); + regmap_write(mvc->regmap, TEGRA210_MVC_CFG_RAM_DATA, + coef); + + return 0; +} + +static int tegra210_mvc_get_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg; + + if (reg == TEGRA210_MVC_CTRL) { + u32 val; + u8 mute_mask; + + pm_runtime_get_sync(cmpnt->dev); + regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &val); + pm_runtime_put(cmpnt->dev); + + mute_mask = (val >> TEGRA210_MVC_MUTE_SHIFT) & + TEGRA210_MUTE_MASK_EN; + + ucontrol->value.integer.value[0] = mute_mask; + } else { + u8 chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; + s32 val = mvc->volume[chan]; + + if (mvc->curve_type == CURVE_POLY) + val = ((val >> 16) * 100) >> 8; + else { + val = (val * 100) >> 8; + val += 12000; + } + + ucontrol->value.integer.value[0] = val; + } + + return 0; +} + +static void tegra210_mvc_conv_vol(struct tegra210_mvc *mvc, u8 chan, s32 val) +{ + /* + * Volume control read from mixer control is with + * 100x scaling; for CURVE_POLY the reg range + * is 0-100 (linear, Q24) and for CURVE_LINEAR + * it is -120dB to +40dB (Q8) + */ + if (mvc->curve_type == CURVE_POLY) { + if (val > 10000) + val = 10000; + mvc->volume[chan] = ((val * (1<<8)) / 100) << 16; + } else { + val -= 12000; + mvc->volume[chan] = (val * (1<<8)) / 100; + } +} + +static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg; + unsigned int value; + int err; + + pm_runtime_get_sync(cmpnt->dev); + + /* Check if VOLUME_SWITCH is triggered */ + err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SWITCH, + value, !(value & TEGRA210_MVC_VOLUME_SWITCH_MASK), + 10, 10000); + if (err < 0) + goto end; + + if (reg == TEGRA210_MVC_CTRL) { + u8 mute_mask; + + mute_mask = ucontrol->value.integer.value[0]; + + err = regmap_update_bits(mvc->regmap, reg, + TEGRA210_MVC_MUTE_MASK, + mute_mask << TEGRA210_MVC_MUTE_SHIFT); + } else { + u8 chan; + + chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE; + + tegra210_mvc_conv_vol(mvc, chan, + ucontrol->value.integer.value[0]); + + /* Configure init volume same as target volume */ + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan), + mvc->volume[chan]); + + err = regmap_write(mvc->regmap, reg, mvc->volume[chan]); + } + + err |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + +end: + pm_runtime_put(cmpnt->dev); + return err; +} + +static void tegra210_mvc_reset_vol_settings(struct tegra210_mvc *mvc, + struct device *dev) +{ + int i; + + /* Change volume to default init for new curve type */ + if (mvc->curve_type == CURVE_POLY) { + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) + mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_POLY; + } else { + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) + mvc->volume[i] = TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR; + } + + pm_runtime_get_sync(dev); + + /* Program curve type */ + regmap_update_bits(mvc->regmap, TEGRA210_MVC_CTRL, + TEGRA210_MVC_CURVE_TYPE_MASK, + mvc->curve_type << + TEGRA210_MVC_CURVE_TYPE_SHIFT); + + /* Init volume for all channels */ + for (i = 0; i < TEGRA210_MVC_MAX_CHAN_COUNT; i++) { + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, i), + mvc->volume[i]); + regmap_write(mvc->regmap, + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, i), + mvc->volume[i]); + } + + /* Trigger volume switch */ + regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH, + TEGRA210_MVC_VOLUME_SWITCH_MASK, + TEGRA210_MVC_VOLUME_SWITCH_TRIGGER); + + pm_runtime_put(dev); +} + +static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = mvc->curve_type; + + return 0; +} + +static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt); + int value; + + regmap_read(mvc->regmap, TEGRA210_MVC_ENABLE, &value); + if (value & TEGRA210_MVC_EN) { + dev_err(cmpnt->dev, + "Curve type can't be set when MVC is running\n"); + return -EINVAL; + } + + if (mvc->curve_type == ucontrol->value.integer.value[0]) + return 0; + + mvc->curve_type = ucontrol->value.integer.value[0]; + + tegra210_mvc_reset_vol_settings(mvc, cmpnt->dev); + + return 0; +} + +static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + unsigned int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + + tegra_set_cif(mvc->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_mvc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct device *dev = dai->dev; + struct tegra210_mvc *mvc = snd_soc_dai_get_drvdata(dai); + int i, err, val; + + /* SW reset */ + regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1); + + err = regmap_read_poll_timeout(mvc->regmap, TEGRA210_MVC_SOFT_RESET, + val, !val, 10, 10000); + if (err < 0) { + dev_err(dev, "SW reset failed, err = %d\n", err); + return err; + } + + /* Set RX CIF */ + err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_RX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set MVC RX CIF: %d\n", err); + return err; + } + + /* Set TX CIF */ + err = tegra210_mvc_set_audio_cif(mvc, params, TEGRA210_MVC_TX_CIF_CTRL); + if (err) { + dev_err(dev, "Can't set MVC TX CIF: %d\n", err); + return err; + } + + /* Program the poly coefficients */ + for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) { + err = tegra210_mvc_write_ram(mvc, i, gain_params.poly_coeff[i]); + if (err < 0) { + dev_err(dai->dev, "failed to write coefs, err = %d\n", + err); + return err; + } + } + + /* Program poly_n1, poly_n2, duration */ + regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N1, gain_params.poly_n1); + regmap_write(mvc->regmap, TEGRA210_MVC_POLY_N2, gain_params.poly_n2); + regmap_write(mvc->regmap, TEGRA210_MVC_DURATION, gain_params.duration); + + /* Program duration_inv */ + regmap_write(mvc->regmap, TEGRA210_MVC_DURATION_INV, + gain_params.duration_inv); + + return 0; +} + +static struct snd_soc_dai_ops tegra210_mvc_dai_ops = { + .hw_params = tegra210_mvc_hw_params, +}; + +static const char * const tegra210_mvc_curve_type_text[] = { + "Poly", + "Linear", +}; + +static const struct soc_enum tegra210_mvc_curve_type_ctrl = + SOC_ENUM_SINGLE_EXT(2, tegra210_mvc_curve_type_text); + +#define TEGRA210_MVC_VOL_CTRL(chan) \ + SOC_SINGLE_EXT("Channel" #chan " Volume", \ + TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_TARGET_VOL, \ + (chan - 1)), \ + 0, 16000, 0, tegra210_mvc_get_vol, \ + tegra210_mvc_put_vol) + +static const struct snd_kcontrol_new tegra210_mvc_vol_ctrl[] = { + /* Per channel volume control */ + TEGRA210_MVC_VOL_CTRL(1), + TEGRA210_MVC_VOL_CTRL(2), + TEGRA210_MVC_VOL_CTRL(3), + TEGRA210_MVC_VOL_CTRL(4), + TEGRA210_MVC_VOL_CTRL(5), + TEGRA210_MVC_VOL_CTRL(6), + TEGRA210_MVC_VOL_CTRL(7), + TEGRA210_MVC_VOL_CTRL(8), + + /* Per channel mute */ + SOC_SINGLE_EXT("Per Chan Mute Mask", + TEGRA210_MVC_CTRL, 0, TEGRA210_MUTE_MASK_EN, 0, + tegra210_mvc_get_vol, tegra210_mvc_put_vol), + + SOC_ENUM_EXT("Curve Type", tegra210_mvc_curve_type_ctrl, + tegra210_mvc_get_curve_type, tegra210_mvc_put_curve_type), +}; + +static struct snd_soc_dai_driver tegra210_mvc_dais[] = { + /* Input */ + { + .name = "MVC-RX-CIF", + .playback = { + .stream_name = "RX-CIF-Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "RX-CIF-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + }, + + /* Output */ + { + .name = "MVC-TX-CIF", + .playback = { + .stream_name = "TX-CIF-Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "TX-CIF-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_mvc_dai_ops, + } +}; + +static const struct snd_soc_dapm_widget tegra210_mvc_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_MVC_ENABLE, + TEGRA210_MVC_EN_SHIFT, 0), +}; + +#define MVC_ROUTES(sname) \ + { "RX XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX-CIF-" sname, NULL, "TX" }, \ + { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \ + { "XBAR-RX", NULL, "TX XBAR-" sname } + +static const struct snd_soc_dapm_route tegra210_mvc_routes[] = { + { "TX", NULL, "RX" }, + MVC_ROUTES("Playback"), + MVC_ROUTES("Capture"), +}; + +static const struct snd_soc_component_driver tegra210_mvc_cmpnt = { + .dapm_widgets = tegra210_mvc_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_mvc_widgets), + .dapm_routes = tegra210_mvc_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_mvc_routes), + .controls = tegra210_mvc_vol_ctrl, + .num_controls = ARRAY_SIZE(tegra210_mvc_vol_ctrl), +}; + +static bool tegra210_mvc_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_STATUS ... TEGRA210_MVC_CONFIG_ERR_TYPE: + return true; + default: + return false; + }; +} + +static bool tegra210_mvc_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_INT_MASK ... TEGRA210_MVC_RX_CIF_CTRL: + case TEGRA210_MVC_TX_INT_MASK ... TEGRA210_MVC_TX_CIF_CTRL: + case TEGRA210_MVC_ENABLE ... TEGRA210_MVC_CG: + case TEGRA210_MVC_CTRL ... TEGRA210_MVC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mvc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_MVC_RX_STATUS: + case TEGRA210_MVC_RX_INT_STATUS: + case TEGRA210_MVC_RX_INT_SET: + + case TEGRA210_MVC_TX_STATUS: + case TEGRA210_MVC_TX_INT_STATUS: + case TEGRA210_MVC_TX_INT_SET: + + case TEGRA210_MVC_SOFT_RESET: + case TEGRA210_MVC_STATUS: + case TEGRA210_MVC_INT_STATUS: + case TEGRA210_MVC_SWITCH: + case TEGRA210_MVC_CFG_RAM_CTRL: + case TEGRA210_MVC_CFG_RAM_DATA: + case TEGRA210_MVC_PEAK_VALUE: + case TEGRA210_MVC_CTRL: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_mvc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_MVC_CONFIG_ERR_TYPE, + .writeable_reg = tegra210_mvc_wr_reg, + .readable_reg = tegra210_mvc_rd_reg, + .volatile_reg = tegra210_mvc_volatile_reg, + .reg_defaults = tegra210_mvc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_mvc_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_mvc_of_match[] = { + { .compatible = "nvidia,tegra210-mvc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_mvc_of_match); + +static int tegra210_mvc_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_mvc *mvc; + void __iomem *regs; + int err; + + mvc = devm_kzalloc(dev, sizeof(*mvc), GFP_KERNEL); + if (!mvc) + return -ENOMEM; + + dev_set_drvdata(dev, mvc); + + mvc->curve_type = CURVE_LINEAR; + mvc->ctrl_value = TEGRA210_MVC_CTRL_DEFAULT; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + mvc->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_mvc_regmap_config); + if (IS_ERR(mvc->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(mvc->regmap); + } + + regcache_cache_only(mvc->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_mvc_cmpnt, + tegra210_mvc_dais, + ARRAY_SIZE(tegra210_mvc_dais)); + if (err) { + dev_err(dev, "can't register MVC component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + tegra210_mvc_reset_vol_settings(mvc, &pdev->dev); + + return 0; +} + +static int tegra210_mvc_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_mvc_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, + tegra210_mvc_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_mvc_driver = { + .driver = { + .name = "tegra210-mvc", + .of_match_table = tegra210_mvc_of_match, + .pm = &tegra210_mvc_pm_ops, + }, + .probe = tegra210_mvc_platform_probe, + .remove = tegra210_mvc_platform_remove, +}; +module_platform_driver(tegra210_mvc_driver) + +MODULE_AUTHOR("Arun Shamanna Lakshmi aruns@nvidia.com"); +MODULE_DESCRIPTION("Tegra210 MVC ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_mvc.h b/sound/soc/tegra/tegra210_mvc.h new file mode 100644 index 0000000..def29c4 --- /dev/null +++ b/sound/soc/tegra/tegra210_mvc.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_mvc.h - Definitions for Tegra210 MVC driver + * + * Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_MVC_H__ +#define __TEGRA210_MVC_H__ + +/* + * MVC_RX registers are with respect to XBAR. + * The data comes from XBAR to MVC. + */ +#define TEGRA210_MVC_RX_STATUS 0x0c +#define TEGRA210_MVC_RX_INT_STATUS 0x10 +#define TEGRA210_MVC_RX_INT_MASK 0x14 +#define TEGRA210_MVC_RX_INT_SET 0x18 +#define TEGRA210_MVC_RX_INT_CLEAR 0x1c +#define TEGRA210_MVC_RX_CIF_CTRL 0x20 + +/* + * MVC_TX registers are with respect to XBAR. + * The data goes out of MVC. + */ +#define TEGRA210_MVC_TX_STATUS 0x4c +#define TEGRA210_MVC_TX_INT_STATUS 0x50 +#define TEGRA210_MVC_TX_INT_MASK 0x54 +#define TEGRA210_MVC_TX_INT_SET 0x58 +#define TEGRA210_MVC_TX_INT_CLEAR 0x5c +#define TEGRA210_MVC_TX_CIF_CTRL 0x60 + +/* Register offsets from TEGRA210_MVC*_BASE */ +#define TEGRA210_MVC_ENABLE 0x80 +#define TEGRA210_MVC_SOFT_RESET 0x84 +#define TEGRA210_MVC_CG 0x88 +#define TEGRA210_MVC_STATUS 0x90 +#define TEGRA210_MVC_INT_STATUS 0x94 +#define TEGRA210_MVC_CTRL 0xa8 +#define TEGRA210_MVC_SWITCH 0xac +#define TEGRA210_MVC_INIT_VOL 0xb0 +#define TEGRA210_MVC_TARGET_VOL 0xd0 +#define TEGRA210_MVC_DURATION 0xf0 +#define TEGRA210_MVC_DURATION_INV 0xf4 +#define TEGRA210_MVC_POLY_N1 0xf8 +#define TEGRA210_MVC_POLY_N2 0xfc +#define TEGRA210_MVC_PEAK_CTRL 0x100 +#define TEGRA210_MVC_CFG_RAM_CTRL 0x104 +#define TEGRA210_MVC_CFG_RAM_DATA 0x108 +#define TEGRA210_MVC_PEAK_VALUE 0x10c +#define TEGRA210_MVC_CONFIG_ERR_TYPE 0x12c + +/* Fields in TEGRA210_MVC_ENABLE */ +#define TEGRA210_MVC_EN_SHIFT 0 +#define TEGRA210_MVC_EN (1 << TEGRA210_MVC_EN_SHIFT) + +#define TEGRA210_MVC_MUTE_SHIFT 8 +#define TEGRA210_MUTE_MASK_EN 0xff +#define TEGRA210_MVC_MUTE_MASK (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) +#define TEGRA210_MVC_MUTE_EN (TEGRA210_MUTE_MASK_EN << TEGRA210_MVC_MUTE_SHIFT) + +#define TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT 30 +#define TEGRA210_MVC_PER_CHAN_CTRL_EN_MASK (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT) +#define TEGRA210_MVC_PER_CHAN_CTRL_EN (1 << TEGRA210_MVC_PER_CHAN_CTRL_EN_SHIFT) + +#define TEGRA210_MVC_CURVE_TYPE_SHIFT 1 +#define TEGRA210_MVC_CURVE_TYPE_MASK (1 << TEGRA210_MVC_CURVE_TYPE_SHIFT) + +#define TEGRA210_MVC_VOLUME_SWITCH_SHIFT 2 +#define TEGRA210_MVC_VOLUME_SWITCH_MASK (1 << TEGRA210_MVC_VOLUME_SWITCH_SHIFT) +#define TEGRA210_MVC_VOLUME_SWITCH_TRIGGER (1 << TEGRA210_MVC_VOLUME_SWITCH_SHIFT) +#define TEGRA210_MVC_CTRL_DEFAULT 0x40000003 + +#define TEGRA210_MVC_INIT_VOL_DEFAULT_POLY 0x01000000 +#define TEGRA210_MVC_INIT_VOL_DEFAULT_LINEAR 0x00000000 + +/* Fields in TEGRA210_MVC ram ctrl */ +#define TEGRA210_MVC_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_MVC_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_MVC_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_MVC_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_MVC_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_SHIFT 0 +#define TEGRA210_MVC_CFG_RAM_CTRL_ADDR_MASK (0x1ff << TEGRA210_MVC_CFG_RAM_CTRL_ADDR_SHIFT) + +#define REG_SIZE 4 +#define TEGRA210_MVC_MAX_CHAN_COUNT 8 +#define TEGRA210_MVC_REG_OFFSET(reg, i) (reg + (REG_SIZE * i)) + +#define NUM_GAIN_POLY_COEFFS 9 + +enum { + CURVE_POLY, + CURVE_LINEAR, +}; + +struct tegra210_mvc_gain_params { + int poly_coeff[NUM_GAIN_POLY_COEFFS]; + int poly_n1; + int poly_n2; + int duration; + int duration_inv; +}; + +struct tegra210_mvc { + int volume[TEGRA210_MVC_MAX_CHAN_COUNT]; + unsigned int curve_type; + unsigned int ctrl_value; + struct regmap *regmap; +}; + +#endif
On Fri, Aug 27, 2021 at 03:03:52PM +0530, Sameer Pujar wrote:
The Master Volume Control (MVC) provides gain or attenuation to a digital signal path. It can be used in input or output signal path for per-stream volume control or it can be used as master volume control. The MVC block has one input and one output. The input digital stream can be mono or multi-channel (up to 7.1 channels) stream. An independent mute control is also included in the MVC block.
Looks like it's also got a little bit of other DSP in there (a simple EQ?). Not that it really matters.
- if (reg == TEGRA210_MVC_CTRL) {
u32 val;
u8 mute_mask;
- } else {
u8 chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE;
s32 val = mvc->volume[chan];
It's not clear to me why we're using the same callbacks for the volume and mute settings - there's no shared code on the read path and only a tiny bit on the write path.
- err |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
TEGRA210_MVC_VOLUME_SWITCH_MASK,
TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
+end:
- pm_runtime_put(cmpnt->dev);
- return err;
+}
_put() should return 0 if there's no change or 1 for a change.
- /* SW reset */
- regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
What about all the cached values in the regmap, won't they get out of sync? Especially things like volume and mute, it looks like the mute just gets written directly to the regmap and not otherwise saved.
Hi Mark,
Thank you for review.
On 9/3/2021 11:43 PM, Mark Brown wrote:
On Fri, Aug 27, 2021 at 03:03:52PM +0530, Sameer Pujar wrote:
The Master Volume Control (MVC) provides gain or attenuation to a digital signal path. It can be used in input or output signal path for per-stream volume control or it can be used as master volume control. The MVC block has one input and one output. The input digital stream can be mono or multi-channel (up to 7.1 channels) stream. An independent mute control is also included in the MVC block.
Looks like it's also got a little bit of other DSP in there (a simple EQ?). Not that it really matters.
MVC does not have EQ block. In fact it is part of another processing module, the driver for which is not part of this series.
- if (reg == TEGRA210_MVC_CTRL) {
u32 val;
u8 mute_mask;
- } else {
u8 chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE;
s32 val = mvc->volume[chan];
It's not clear to me why we're using the same callbacks for the volume and mute settings - there's no shared code on the read path and only a tiny bit on the write path.
The volume switch trigger is common in put(). The get() is probably influenced from the put() and common function is maintained. If it makes more clear I will separate these out.
- err |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
TEGRA210_MVC_VOLUME_SWITCH_MASK,
TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
+end:
- pm_runtime_put(cmpnt->dev);
- return err;
+}
_put() should return 0 if there's no change or 1 for a change.
done
- /* SW reset */
- regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
What about all the cached values in the regmap, won't they get out of sync? Especially things like volume and mute, it looks like the mute just gets written directly to the regmap and not otherwise saved.
1. I think original idea was to disable MVC (forcefully) before new configurations are applied and eventually it gets enabled via DAPM path. DAPM path handles disable also, but sometimes MVC may get stuck in enable state (due to a previous usage) when all the data in pipeline is not processed. My understanding is that reset is restricted to this alone. The volume/mute registers seem not to be affected by reset. However I will confirm with HW about the reset behavior and affected register map. Thanks for pointing this.
2. The mute is part of volatile register and volume is not. If the system is muted and any volume settings are made, the system is unmuted automatically. For this reason mute is always read from HW. For volume it is saved for local computation.
On 9/7/2021 1:35 PM, Sameer Pujar wrote:
On 9/3/2021 11:43 PM, Mark Brown wrote:
On Fri, Aug 27, 2021 at 03:03:52PM +0530, Sameer Pujar wrote:
- /* SW reset */
- regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
What about all the cached values in the regmap, won't they get out of sync? Especially things like volume and mute, it looks like the mute just gets written directly to the regmap and not otherwise saved.
- I think original idea was to disable MVC (forcefully) before new
configurations are applied and eventually it gets enabled via DAPM path. DAPM path handles disable also, but sometimes MVC may get stuck in enable state (due to a previous usage) when all the data in pipeline is not processed. My understanding is that reset is restricted to this alone. The volume/mute registers seem not to be affected by reset. However I will confirm with HW about the reset behavior and affected register map. Thanks for pointing this.
I confirmed the behavior with HW folk here. The reset above clears all FSM, flushes flow control of FIFO and resets the state registers. It also brings module back to disabled state (without flushing the data in the pipe). There is no impact on the register cache, as state registers are anyway volatile and module disable is applicable only when it was hung in previous usage. Otherwise DAPM would disable the module during session close.
On Thu, Sep 09, 2021 at 06:33:33PM +0530, Sameer Pujar wrote:
On 9/7/2021 1:35 PM, Sameer Pujar wrote:
On 9/3/2021 11:43 PM, Mark Brown wrote:
On Fri, Aug 27, 2021 at 03:03:52PM +0530, Sameer Pujar wrote:
- /* SW reset */
- regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
What about all the cached values in the regmap, won't they get out of sync? Especially things like volume and mute, it looks like the mute just gets written directly to the regmap and not otherwise saved.
- I think original idea was to disable MVC (forcefully) before new
configurations are applied and eventually it gets enabled via DAPM path. DAPM path handles disable also, but sometimes MVC may get stuck in enable state (due to a previous usage) when all the data in pipeline is not processed. My understanding is that reset is restricted to this alone. The volume/mute registers seem not to be affected by reset. However I will confirm with HW about the reset behavior and affected register map. Thanks for pointing this.
I confirmed the behavior with HW folk here. The reset above clears all FSM, flushes flow control of FIFO and resets the state registers. It also brings module back to disabled state (without flushing the data in the pipe). There is no impact on the register cache, as state registers are anyway volatile and module disable is applicable only when it was hung in previous usage. Otherwise DAPM would disable the module during session close.
This needs to be *much* clearer in the code, it looks like a bug at the minute. It's very surprising that some of the registers wouldn't be affected by a reset.
On 9/9/2021 7:50 PM, Mark Brown wrote:
On Thu, Sep 09, 2021 at 06:33:33PM +0530, Sameer Pujar wrote:
On 9/7/2021 1:35 PM, Sameer Pujar wrote:
On 9/3/2021 11:43 PM, Mark Brown wrote:
On Fri, Aug 27, 2021 at 03:03:52PM +0530, Sameer Pujar wrote:
- /* SW reset */
- regmap_write(mvc->regmap, TEGRA210_MVC_SOFT_RESET, 1);
What about all the cached values in the regmap, won't they get out of sync? Especially things like volume and mute, it looks like the mute just gets written directly to the regmap and not otherwise saved.
- I think original idea was to disable MVC (forcefully) before new
configurations are applied and eventually it gets enabled via DAPM path. DAPM path handles disable also, but sometimes MVC may get stuck in enable state (due to a previous usage) when all the data in pipeline is not processed. My understanding is that reset is restricted to this alone. The volume/mute registers seem not to be affected by reset. However I will confirm with HW about the reset behavior and affected register map. Thanks for pointing this.
I confirmed the behavior with HW folk here. The reset above clears all FSM, flushes flow control of FIFO and resets the state registers. It also brings module back to disabled state (without flushing the data in the pipe). There is no impact on the register cache, as state registers are anyway volatile and module disable is applicable only when it was hung in previous usage. Otherwise DAPM would disable the module during session close.
This needs to be*much* clearer in the code, it looks like a bug at the minute. It's very surprising that some of the registers wouldn't be affected by a reset.
I will put additional comments to make it more clear and tag it as a 'soft reset' instead of 'reset' as HW spec defines it.
On 9/3/2021 11:43 PM, Mark Brown wrote:
- err |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
TEGRA210_MVC_VOLUME_SWITCH_MASK,
TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
+end:
- pm_runtime_put(cmpnt->dev);
- return err;
+}
_put() should return 0 if there's no change or 1 for a change.
So this means, no need to return any error value and just return 0 in such cases?
On Mon, Sep 13, 2021 at 10:32:32AM +0530, Sameer Pujar wrote:
On 9/3/2021 11:43 PM, Mark Brown wrote:
- err |= regmap_update_bits(mvc->regmap, TEGRA210_MVC_SWITCH,
TEGRA210_MVC_VOLUME_SWITCH_MASK,
TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
+end:
- pm_runtime_put(cmpnt->dev);
- return err;
+}
_put() should return 0 if there's no change or 1 for a change.
So this means, no need to return any error value and just return 0 in such cases?
If there's an error you should return that instead.
The Sampling Frequency Converter (SFC) converts the sampling frequency of the input signal from one frequency to another. It supports sampling frequency conversions of streams of up to two channels (stereo).
This patch registers SFC driver with ASoC framework. The component driver exposes DAPM widgets, routes and kcontrols for the device. The DAI driver exposes SFC interfaces, which can be used to connect different components in the ASoC layer. Makefile and Kconfig support is added to allow build the driver. It can be enabled in the DT via "nvidia,tegra210-sfc" compatible binding.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/Kconfig | 9 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra210_sfc.c | 3542 ++++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra210_sfc.h | 78 + 4 files changed, 3631 insertions(+) create mode 100644 sound/soc/tegra/tegra210_sfc.c create mode 100644 sound/soc/tegra/tegra210_sfc.h
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index b8825e9..102564e 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -117,6 +117,15 @@ config SND_SOC_TEGRA210_MVC per-stream volume control or for master volume control. Say Y or M if you want to add support for Tegra210 MVC module.
+config SND_SOC_TEGRA210_SFC + tristate "Tegra210 SFC module" + help + Config to enable the Sampling Frequency Converter (SFC) which + converts the sampling frequency of input signal to another + frequency. It supports sampling frequency conversion of streams + upto 2 channels (stereo). + Say Y or M if you want to add support for Tegra210 SFC module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index b58d041..bb0cf3a 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -14,6 +14,7 @@ snd-soc-tegra210-i2s-objs := tegra210_i2s.o snd-soc-tegra186-dspk-objs := tegra186_dspk.o snd-soc-tegra210-admaif-objs := tegra210_admaif.o snd-soc-tegra210-mvc-objs := tegra210_mvc.o +snd-soc-tegra210-sfc-objs := tegra210_sfc.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -28,6 +29,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_I2S) += snd-soc-tegra210-i2s.o obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o +obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o
# Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c new file mode 100644 index 0000000..a23e8fd1 --- /dev/null +++ b/sound/soc/tegra/tegra210_sfc.c @@ -0,0 +1,3542 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_sfc.c - Tegra210 SFC driver +// +// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_sfc.h" +#include "tegra_cif.h" + +#define UNSUPP_CONV ((void *)(-EOPNOTSUPP)) +#define BYPASS_CONV NULL + +static const struct reg_default tegra210_sfc_reg_defaults[] = { + { TEGRA210_SFC_RX_INT_MASK, 0x00000001}, + { TEGRA210_SFC_RX_CIF_CTRL, 0x00007700}, + { TEGRA210_SFC_TX_INT_MASK, 0x00000001}, + { TEGRA210_SFC_TX_CIF_CTRL, 0x00007700}, + { TEGRA210_SFC_CG, 0x1}, + { TEGRA210_SFC_CFG_RAM_CTRL, 0x00004000}, +}; + +static const int tegra210_sfc_rates[TEGRA210_SFC_NUM_RATES] = { + 8000, + 11025, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000, + 88200, + 96000, + 176400, + 192000, +}; + +/* coeff RAM tables required for SFC */ +static u32 coef_8to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_8to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_8to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001//output gain +}; + +static u32 coef_8to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//header + 0x000005e1,//input gain + 0x00dca92f, 0xff45647a, 0x0046b59c, + 0x00429d1e, 0xff4fec62, 0x00516d30, + 0xffdea779, 0xff5e08ba, 0x0060185e, + 0xffafbab2, 0xff698d5a, 0x006ce3ae, + 0xff9a82d2, 0xff704674, 0x007633c5, + 0xff923433, 0xff721128, 0x007cff42, + 0x00000003//output gain +}; + +static u32 coef_8to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_8to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0156105,//interpolation + IIR filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//ouptut gain + 0x0021a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003,//Output gain + 0x00000204,//Farrow filter + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_8to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//interpolation + IIR Filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//ouptut gain + 0x0000a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003//output gain +}; + +static u32 coef_8to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0024a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_8to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0000a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003//output gain +}; + +static u32 coef_11to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_11to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_11to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_11to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_11to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_11to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_16to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000fa103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000003,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_16to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_16to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0015a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003,//output gain + 0x00005105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_16to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_16to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//interpolation + IIR filter + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000002,//output gain + 0x0021a102,//interpolation + IIR filter + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000003,//output gain + 0x002c0204,//Farrow Filter + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005101,//IIR Filter + Decimator + 0x0000203c,//input gain + 0x00f52d35, 0xff2e2162, 0x005a21e0, + 0x00c6f0f0, 0xff2ecd69, 0x006fa78d, + 0x00000001//output gain +}; + +static u32 coef_16to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//interpolation + IIR Filter + 0x00000784,//input gain + 0x00cc516e, 0xff2c9639, 0x005ad5b3, + 0x0013ad0d, 0xff3d4799, 0x0063ce75, + 0xffb6f398, 0xff5138d1, 0x006e9e1f, + 0xff9186e5, 0xff5f96a4, 0x0076a86e, + 0xff82089c, 0xff676b81, 0x007b9f8a, + 0xff7c48a5, 0xff6a31e7, 0x007ebb7b, + 0x00000003//output gain +}; + +static u32 coef_16to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0000a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003//output gain +}; + +static u32 coef_16to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0024a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_16to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x0000a102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000003//output gain +}; + +static u32 coef_22to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_22to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000001//output gain +}; + +static u32 coef_22to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_22to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_22to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_22to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_22to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_24to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//header + 0x000005e1,//input gain + 0x00dca92f, 0xff45647a, 0x0046b59c, + 0x00429d1e, 0xff4fec62, 0x00516d30, + 0xffdea779, 0xff5e08ba, 0x0060185e, + 0xffafbab2, 0xff698d5a, 0x006ce3ae, + 0xff9a82d2, 0xff704674, 0x007633c5, + 0xff923433, 0xff721128, 0x007cff42, + 0x00000001//output gain +}; + +static u32 coef_24to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_24to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000002,//output gain + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_24to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000002,//output gain + 0x001b6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x00265204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_24to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00009102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_24to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001//output gain +}; + +static u32 coef_24to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_24to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x002f0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001//output gain +}; + +static u32 coef_24to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_24to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_24to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00006102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002//output gain +}; + +static u32 coef_32to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000ca102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000003,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x0000d102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_32to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000fa103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000003,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_32to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000ca102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000003,//output gain + 0x0000d102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_32to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000001//output gain +}; + +static u32 coef_32to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0015a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003,//output gain + 0x00005105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_32to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001//output gain +}; + +static u32 coef_32to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x0000a105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000003//output gain +}; + +static u32 coef_32to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0018a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003,//output gain + 0x00000204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_32to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x0000a102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000003//output gain +}; + +static u32 coef_44to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00120104,//IIR Filter + 0x00000af2,//input gain + 0x0057eebe, 0xff1e9863, 0x00652604, + 0xff7206ea, 0xff22ad7e, 0x006d47e1, + 0xff42a4d7, 0xff26e722, 0x0075fd83, + 0xff352f66, 0xff29312b, 0x007b986b, + 0xff310a07, 0xff296f51, 0x007eca7c, + 0x00000001,//output gain + 0x001d9204,//Farrow Filter + decimation + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_44to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00126104,//IIR Filter + interpolation + 0x00000af2,//input gain + 0x0057eebe, 0xff1e9863, 0x00652604, + 0xff7206ea, 0xff22ad7e, 0x006d47e1, + 0xff42a4d7, 0xff26e722, 0x0075fd83, + 0xff352f66, 0xff29312b, 0x007b986b, + 0xff310a07, 0xff296f51, 0x007eca7c, + 0x00000002,//output gain + 0x001d9204,//Farrow Filter + decimation + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_44to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000015f,//input gain + 0x00a7909c, 0xff241c71, 0x005f5e00, + 0xffca77f4, 0xff20dd50, 0x006855eb, + 0xff86c552, 0xff18137a, 0x00773648, + 0x00000002,//output gain + 0x00186102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00239204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_44to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00235204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000001//output gain +}; + +static u32 coef_44to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_44to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_44to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_44to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_48to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//IIR Filter + Decimator + 0x00000e00,//input gain + 0x00e2e000, 0xff6e1a00, 0x002aaa00, + 0x00610a00, 0xff5dda00, 0x003ccc00, + 0x00163a00, 0xff3c0400, 0x00633200, + 0x00000001,//output gain + 0x00005105,//IIR Filter + Decimator + 0x0000d649,//input gain + 0x00e87afb, 0xff5f69d0, 0x003df3cf, + 0x007ce488, 0xff99a5c8, 0x0056a6a0, + 0x00344928, 0xffcba3e5, 0x006be470, + 0x00137aa7, 0xffe60276, 0x00773410, + 0x0005fa2a, 0xfff1ac11, 0x007c795b, + 0x00012d36, 0xfff5eca2, 0x007f10ef, + 0x00000001//output gain +}; + +static u32 coef_48to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//IIR Filter + Decimator + 0x00000784,//input gain + 0x00cc516e, 0xff2c9639, 0x005ad5b3, + 0x0013ad0d, 0xff3d4799, 0x0063ce75, + 0xffb6f398, 0xff5138d1, 0x006e9e1f, + 0xff9186e5, 0xff5f96a4, 0x0076a86e, + 0xff82089c, 0xff676b81, 0x007b9f8a, + 0xff7c48a5, 0xff6a31e7, 0x007ebb7b, + 0x00000001//output gain +}; + +static u32 coef_48to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00156105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000002,//output gain + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_48to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d029,//input gain + 0x00f2a98b, 0xff92aa71, 0x001fcd16, + 0x00ae9004, 0xffb85140, 0x0041813a, + 0x007f8ed1, 0xffd585fc, 0x006a69e6, + 0x00000002,//output gain + 0x001b6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x00265204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_48to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00230204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001//output gain +}; + +static u32 coef_48to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002//output gain +}; + +static u32 coef_48to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00186102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00246102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x002f0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001//output gain +}; + +static u32 coef_48to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000002,//output gain + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_88to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000057,//input gain + 0x00a8e717, 0xff1c748d, 0x0065b976, + 0xffcbccab, 0xff190aff, 0x006cc1cf, + 0xff871ce1, 0xff10d878, 0x0078cfc5, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000002,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_88to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_88to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002//output gain +}; + +static u32 coef_88to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000002,//output gain + 0x00186102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_96to8[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to11[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00009105,//header + 0x00000292,//input gain + 0x00e4320a, 0xff41d2d9, 0x004911ac, + 0x005dd9e3, 0xff4c7d80, 0x0052103e, + 0xfff8ebef, 0xff5b6fab, 0x005f0a0d, + 0xffc4b414, 0xff68582c, 0x006b38e5, + 0xffabb861, 0xff704bec, 0x0074de52, + 0xffa19f4c, 0xff729059, 0x007c7e90, + 0x00000001//output gain +}; + +static u32 coef_96to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a5204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_96to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001a0204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_96to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000f6103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002,//output gain + 0x001b6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00260204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001//output gain +}; + +static u32 coef_96to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00006103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000002//output gain +}; + +static u32 coef_176to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000057,//input gain + 0x00a8e717, 0xff1c748d, 0x0065b976, + 0xffcbccab, 0xff190aff, 0x006cc1cf, + 0xff871ce1, 0xff10d878, 0x0078cfc5, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00000138,//input gain + 0x00d5d232, 0xff2a3bf8, 0x005a785c, + 0x0034001b, 0xff283109, 0x006462a6, + 0xffe6746a, 0xff1fb09c, 0x00758a91, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000005f3,//input gain + 0x00d816d6, 0xff385383, 0x004fe566, + 0x003c548d, 0xff38c23d, 0x005d0b1c, + 0xfff02f7d, 0xff31e983, 0x0072d65d, + 0x00000001,//output gain + 0x00179204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x00001685,//input gain + 0x00f53ae9, 0xff52f196, 0x003e3e08, + 0x00b9f857, 0xff5d8985, 0x0050070a, + 0x008c3e86, 0xff6053f0, 0x006d98ef, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_176to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_176to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000001//output gain +}; + +static u32 coef_176to192[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000002,//output gain + 0x00005204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000 +}; + +static u32 coef_192to16[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x0000007d,//input gain + 0x007d1f20, 0xff1a540e, 0x00678bf9, + 0xff916625, 0xff16b0ff, 0x006e433a, + 0xff5af660, 0xff0eb91f, 0x00797356, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to22[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c0102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000001,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to24[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001,//output gain + 0x00185102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to32[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c9102,//header + 0x000005d6,//input gain + 0x00c6543e, 0xff342935, 0x0052f116, + 0x000a1d78, 0xff3330c0, 0x005f88a3, + 0xffbee7c0, 0xff2b5ba5, 0x0073eb26, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to44[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00235102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to48[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c5102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001,//output gain + 0x00005102,//header + 0x0001d727,//input gain + 0x00fc2fc7, 0xff9bb27b, 0x001c564c, + 0x00e55557, 0xffcadd5b, 0x003d80ba, + 0x00d13397, 0xfff232f8, 0x00683337, + 0x00000001//output gain +}; + +static u32 coef_192to88[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00175204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x000013d9,//input gain + 0x00ebd477, 0xff4ce383, 0x0042049d, + 0x0089c278, 0xff54414d, 0x00531ded, + 0x004a5e07, 0xff53cf41, 0x006efbdc, + 0x00000001//output gain +}; + +static u32 coef_192to96[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x00005103,//header + 0x000001e0,//input gain + 0x00de44c0, 0xff380b7f, 0x004ffc73, + 0x00494b44, 0xff3d493a, 0x005908bf, + 0xffe9a3c8, 0xff425647, 0x006745f7, + 0xffc42d61, 0xff40a6c7, 0x00776709, + 0x00000001//output gain +}; + +static u32 coef_192to176[TEGRA210_SFC_COEF_RAM_DEPTH] = { + 0x000c6102,//header + 0x000000af,//input gain + 0x00c65663, 0xff23d2ce, 0x005f97d6, + 0x00086ad6, 0xff20ec4f, 0x00683201, + 0xffbbbef6, 0xff184447, 0x00770963, + 0x00000002,//output gain + 0x00170204,//farrow + 0x000aaaab, + 0xffaaaaab, + 0xfffaaaab, + 0x00555555, + 0xff600000, + 0xfff55555, + 0x00155555, + 0x00055555, + 0xffeaaaab, + 0x00200000, + 0x00005102,//header + 0x0000010a,//input gain + 0x00c93dc4, 0xff26f5f6, 0x005d1041, + 0x001002c4, 0xff245b76, 0x00666002, + 0xffc30a45, 0xff1baecd, 0x00765921, + 0x00000001//output gain +}; + +/* + * Coefficient table for various sample rate conversions. The sample + * rates available are as per tegra210_sfc_rates[]. + */ +static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { + /* Convertions from 8 kHz */ + { + BYPASS_CONV, + coef_8to11, + coef_8to16, + coef_8to22, + coef_8to24, + coef_8to32, + coef_8to44, + coef_8to48, + coef_8to88, + coef_8to96, + UNSUPP_CONV, + UNSUPP_CONV, + }, + /* Convertions from 11.025 kHz */ + { + coef_11to8, + BYPASS_CONV, + coef_11to16, + coef_11to22, + coef_11to24, + coef_11to32, + coef_11to44, + coef_11to48, + coef_11to88, + coef_11to96, + UNSUPP_CONV, + UNSUPP_CONV, + }, + /* Convertions from 16 kHz */ + { + coef_16to8, + coef_16to11, + BYPASS_CONV, + coef_16to22, + coef_16to24, + coef_16to32, + coef_16to44, + coef_16to48, + coef_16to88, + coef_16to96, + coef_16to176, + coef_16to192, + }, + /* Convertions from 22.05 kHz */ + { + coef_22to8, + coef_22to11, + coef_22to16, + BYPASS_CONV, + coef_22to24, + coef_22to32, + coef_22to44, + coef_22to48, + coef_22to88, + coef_22to96, + coef_22to176, + coef_22to192, + }, + /* Convertions from 24 kHz */ + { + coef_24to8, + coef_24to11, + coef_24to16, + coef_24to22, + BYPASS_CONV, + coef_24to32, + coef_24to44, + coef_24to48, + coef_24to88, + coef_24to96, + coef_24to176, + coef_24to192, + }, + /* Convertions from 32 kHz */ + { + coef_32to8, + coef_32to11, + coef_32to16, + coef_32to22, + coef_32to24, + BYPASS_CONV, + coef_32to44, + coef_32to48, + coef_32to88, + coef_32to96, + coef_32to176, + coef_32to192, + }, + /* Convertions from 44.1 kHz */ + { + coef_44to8, + coef_44to11, + coef_44to16, + coef_44to22, + coef_44to24, + coef_44to32, + BYPASS_CONV, + coef_44to48, + coef_44to88, + coef_44to96, + coef_44to176, + coef_44to192, + }, + /* Convertions from 48 kHz */ + { + coef_48to8, + coef_48to11, + coef_48to16, + coef_48to22, + coef_48to24, + coef_48to32, + coef_48to44, + BYPASS_CONV, + coef_48to88, + coef_48to96, + coef_48to176, + coef_48to192, + }, + /* Convertions from 88.2 kHz */ + { + coef_88to8, + coef_88to11, + coef_88to16, + coef_88to22, + coef_88to24, + coef_88to32, + coef_88to44, + coef_88to48, + BYPASS_CONV, + coef_88to96, + coef_88to176, + coef_88to192, + }, + /* Convertions from 96 kHz */ + { coef_96to8, + coef_96to11, + coef_96to16, + coef_96to22, + coef_96to24, + coef_96to32, + coef_96to44, + coef_96to48, + coef_96to88, + BYPASS_CONV, + coef_96to176, + coef_96to192, + }, + /* Convertions from 176.4 kHz */ + { + UNSUPP_CONV, + UNSUPP_CONV, + coef_176to16, + coef_176to22, + coef_176to24, + coef_176to32, + coef_176to44, + coef_176to48, + coef_176to88, + coef_176to96, + BYPASS_CONV, + coef_176to192, + }, + /* Convertions from 192 kHz */ + { + UNSUPP_CONV, + UNSUPP_CONV, + coef_192to16, + coef_192to22, + coef_192to24, + coef_192to32, + coef_192to44, + coef_192to48, + coef_192to88, + coef_192to96, + coef_192to176, + BYPASS_CONV, + }, +}; + +static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(dev); + + regcache_cache_only(sfc->regmap, true); + regcache_mark_dirty(sfc->regmap); + + return 0; +} + +static int __maybe_unused tegra210_sfc_runtime_resume(struct device *dev) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(dev); + + regcache_cache_only(sfc->regmap, false); + regcache_sync(sfc->regmap); + + return 0; +} + +static inline void tegra210_sfc_write_ram(struct regmap *regmap, + s32 *data) +{ + int i; + + regmap_write(regmap, TEGRA210_SFC_CFG_RAM_CTRL, + TEGRA210_SFC_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_SFC_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_SFC_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_SFC_COEF_RAM_DEPTH; i++) + regmap_write(regmap, TEGRA210_SFC_CFG_RAM_DATA, data[i]); +} + +static int tegra210_sfc_write_coeff_ram(struct snd_soc_component *cmpnt) +{ + struct tegra210_sfc *sfc = dev_get_drvdata(cmpnt->dev); + s32 *coeff_ram; + + /* Bypass */ + if (sfc->srate_in == sfc->srate_out) + return 0; + + coeff_ram = coef_addr_table[sfc->srate_in][sfc->srate_out]; + if (IS_ERR_OR_NULL(coeff_ram)) { + dev_err(cmpnt->dev, + "Conversion from %d to %d Hz is not supported\n", + sfc->srate_in, sfc->srate_out); + + return PTR_ERR_OR_ZERO(coeff_ram); + } + + tegra210_sfc_write_ram(sfc->regmap, coeff_ram); + + regmap_update_bits(sfc->regmap, + TEGRA210_SFC_COEF_RAM, + TEGRA210_SFC_COEF_RAM_EN, + TEGRA210_SFC_COEF_RAM_EN); + + return 0; +} + +static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + unsigned int channels, audio_bits, path; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EOPNOTSUPP; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = TEGRA_ACIF_BITS_32; + + if (reg == TEGRA210_SFC_RX_CIF_CTRL) + path = SFC_RX_PATH; + else + path = SFC_TX_PATH; + + cif_conf.stereo_conv = sfc->stereo_to_mono[path]; + cif_conf.mono_conv = sfc->mono_to_stereo[path]; + + tegra_set_cif(sfc->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_sfc_soft_reset(struct tegra210_sfc *sfc) +{ + u32 val; + + /* SW reset */ + regmap_update_bits(sfc->regmap, TEGRA210_SFC_SOFT_RESET, + TEGRA210_SFC_SOFT_RESET_EN, 1); + + return regmap_read_poll_timeout(sfc->regmap, + TEGRA210_SFC_SOFT_RESET, + val, + !(val & TEGRA210_SFC_SOFT_RESET_EN), + 10, 10000); +} + +static int tegra210_sfc_rate_to_idx(struct device *dev, int rate, + int *rate_idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tegra210_sfc_rates); i++) { + if (rate == tegra210_sfc_rates[i]) { + *rate_idx = i; + + return 0; + } + } + + dev_err(dev, "Sample rate %d Hz is not supported\n", rate); + + return -EOPNOTSUPP; +} + +static int tegra210_sfc_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + int err; + + regmap_update_bits(sfc->regmap, TEGRA210_SFC_COEF_RAM, + TEGRA210_SFC_COEF_RAM_EN, 0); + + err = tegra210_sfc_soft_reset(sfc); + if (err < 0) { + dev_err(dai->dev, "Failed to reset SFC in %s, err = %d\n", + __func__, err); + + return err; + } + + return 0; +} + +static int tegra210_sfc_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + struct device *dev = dai->dev; + int err; + + err = tegra210_sfc_rate_to_idx(dev, params_rate(params), + &sfc->srate_in); + if (err < 0) + return err; + + err = tegra210_sfc_set_audio_cif(sfc, params, TEGRA210_SFC_RX_CIF_CTRL); + if (err < 0) { + dev_err(dev, "Can't set SFC RX CIF: %d\n", err); + return err; + } + + regmap_write(sfc->regmap, TEGRA210_SFC_RX_FREQ, sfc->srate_in); + + return err; +} + +static int tegra210_sfc_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_sfc *sfc = snd_soc_dai_get_drvdata(dai); + struct device *dev = dai->dev; + int err; + + err = tegra210_sfc_rate_to_idx(dev, params_rate(params), + &sfc->srate_out); + if (err < 0) + return err; + + err = tegra210_sfc_set_audio_cif(sfc, params, TEGRA210_SFC_TX_CIF_CTRL); + if (err < 0) { + dev_err(dev, "Can't set SFC TX CIF: %d\n", err); + return err; + } + + regmap_write(sfc->regmap, TEGRA210_SFC_TX_FREQ, sfc->srate_out); + + return 0; +} + +static int tegra210_sfc_init(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + + return tegra210_sfc_write_coeff_ram(cmpnt); +} + +static int tegra210_sfc_get_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt); + + if (strstr(kcontrol->id.name, "Input Stereo To Mono")) + ucontrol->value.integer.value[0] = + sfc->stereo_to_mono[SFC_RX_PATH]; + else if (strstr(kcontrol->id.name, "Input Mono To Stereo")) + ucontrol->value.integer.value[0] = + sfc->mono_to_stereo[SFC_RX_PATH]; + else if (strstr(kcontrol->id.name, "Output Stereo To Mono")) + ucontrol->value.integer.value[0] = + sfc->stereo_to_mono[SFC_TX_PATH]; + else if (strstr(kcontrol->id.name, "Output Mono To Stereo")) + ucontrol->value.integer.value[0] = + sfc->mono_to_stereo[SFC_TX_PATH]; + + return 0; +} + +static int tegra210_sfc_put_control(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt); + int value = ucontrol->value.integer.value[0]; + + if (strstr(kcontrol->id.name, "Input Stereo To Mono")) + sfc->stereo_to_mono[SFC_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Input Mono To Stereo")) + sfc->mono_to_stereo[SFC_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Output Stereo To Mono")) + sfc->stereo_to_mono[SFC_TX_PATH] = value; + else if (strstr(kcontrol->id.name, "Output Mono To Stereo")) + sfc->mono_to_stereo[SFC_TX_PATH] = value; + + return 0; +} + +static struct snd_soc_dai_ops tegra210_sfc_in_dai_ops = { + .hw_params = tegra210_sfc_in_hw_params, + .startup = tegra210_sfc_startup, +}; + +static struct snd_soc_dai_ops tegra210_sfc_out_dai_ops = { + .hw_params = tegra210_sfc_out_hw_params, +}; + +static struct snd_soc_dai_driver tegra210_sfc_dais[] = { + { + .name = "SFC-RX-CIF", + .playback = { + .stream_name = "RX-CIF-Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "RX-CIF-Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_sfc_in_dai_ops, + }, + { + .name = "SFC-TX-CIF", + .playback = { + .stream_name = "TX-CIF-Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "TX-CIF-Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &tegra210_sfc_out_dai_ops, + }, +}; + +static const struct snd_soc_dapm_widget tegra210_sfc_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT_E("TX", NULL, 0, TEGRA210_SFC_ENABLE, + TEGRA210_SFC_EN_SHIFT, 0, + tegra210_sfc_init, SND_SOC_DAPM_PRE_PMU), +}; + +#define RESAMPLE_ROUTE(sname) \ + { "RX XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "RX XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX-CIF-" sname, NULL, "TX" }, \ + { "TX XBAR-" sname, NULL, "TX-CIF-" sname }, \ + { "XBAR-RX", NULL, "TX XBAR-" sname } + +static const struct snd_soc_dapm_route tegra210_sfc_routes[] = { + { "TX", NULL, "RX" }, + RESAMPLE_ROUTE("Playback"), + RESAMPLE_ROUTE("Capture"), +}; + +static const char * const tegra210_sfc_stereo_conv_text[] = { + "CH0", "CH1", "AVG", +}; + +static const char * const tegra210_sfc_mono_conv_text[] = { + "Zero", "Copy", +}; + +static const struct soc_enum tegra210_sfc_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_stereo_conv_text), + tegra210_sfc_stereo_conv_text); + +static const struct soc_enum tegra210_sfc_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_mono_conv_text), + tegra210_sfc_mono_conv_text); + +static const struct snd_kcontrol_new tegra210_sfc_controls[] = { + SOC_ENUM_EXT("Input Stereo To Mono", tegra210_sfc_stereo_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Input Mono To Stereo", tegra210_sfc_mono_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Output Stereo To Mono", tegra210_sfc_stereo_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), + SOC_ENUM_EXT("Output Mono To Stereo", tegra210_sfc_mono_conv_enum, + tegra210_sfc_get_control, tegra210_sfc_put_control), +}; + +static const struct snd_soc_component_driver tegra210_sfc_cmpnt = { + .dapm_widgets = tegra210_sfc_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_sfc_widgets), + .dapm_routes = tegra210_sfc_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_sfc_routes), + .controls = tegra210_sfc_controls, + .num_controls = ARRAY_SIZE(tegra210_sfc_controls), +}; + +static bool tegra210_sfc_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_INT_MASK ... TEGRA210_SFC_RX_FREQ: + case TEGRA210_SFC_TX_INT_MASK ... TEGRA210_SFC_TX_FREQ: + case TEGRA210_SFC_ENABLE ... TEGRA210_SFC_CG: + case TEGRA210_SFC_COEF_RAM ... TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_STATUS ... TEGRA210_SFC_RX_FREQ: + case TEGRA210_SFC_TX_STATUS ... TEGRA210_SFC_TX_FREQ: + case TEGRA210_SFC_ENABLE ... TEGRA210_SFC_INT_STATUS: + case TEGRA210_SFC_COEF_RAM ... TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_RX_STATUS: + case TEGRA210_SFC_RX_INT_STATUS: + case TEGRA210_SFC_RX_INT_SET: + + case TEGRA210_SFC_TX_STATUS: + case TEGRA210_SFC_TX_INT_STATUS: + case TEGRA210_SFC_TX_INT_SET: + + case TEGRA210_SFC_SOFT_RESET: + case TEGRA210_SFC_STATUS: + case TEGRA210_SFC_INT_STATUS: + case TEGRA210_SFC_CFG_RAM_CTRL: + case TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_sfc_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_SFC_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_sfc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_SFC_CFG_RAM_DATA, + .writeable_reg = tegra210_sfc_wr_reg, + .readable_reg = tegra210_sfc_rd_reg, + .volatile_reg = tegra210_sfc_volatile_reg, + .precious_reg = tegra210_sfc_precious_reg, + .reg_defaults = tegra210_sfc_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_sfc_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_sfc_of_match[] = { + { .compatible = "nvidia,tegra210-sfc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_sfc_of_match); + +static int tegra210_sfc_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_sfc *sfc; + void __iomem *regs; + int err; + + sfc = devm_kzalloc(dev, sizeof(*sfc), GFP_KERNEL); + if (!sfc) + return -ENOMEM; + + dev_set_drvdata(dev, sfc); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + sfc->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_sfc_regmap_config); + if (IS_ERR(sfc->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(sfc->regmap); + } + + regcache_cache_only(sfc->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_sfc_cmpnt, + tegra210_sfc_dais, + ARRAY_SIZE(tegra210_sfc_dais)); + if (err) { + dev_err(dev, "can't register SFC component, err: %d\n", err); + return err; + } + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int tegra210_sfc_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_sfc_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend, + tegra210_sfc_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_sfc_driver = { + .driver = { + .name = "tegra210-sfc", + .of_match_table = tegra210_sfc_of_match, + .pm = &tegra210_sfc_pm_ops, + }, + .probe = tegra210_sfc_platform_probe, + .remove = tegra210_sfc_platform_remove, +}; +module_platform_driver(tegra210_sfc_driver) + +MODULE_AUTHOR("Arun Shamanna Lakshmi aruns@nvidia.com"); +MODULE_DESCRIPTION("Tegra210 SFC ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_sfc.h b/sound/soc/tegra/tegra210_sfc.h new file mode 100644 index 0000000..5a6b66e --- /dev/null +++ b/sound/soc/tegra/tegra210_sfc.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_sfc.h - Definitions for Tegra210 SFC driver + * + * Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_SFC_H__ +#define __TEGRA210_SFC_H__ + +/* + * SFC_RX registers are with respect to XBAR. + * The data comes from XBAR to SFC. + */ +#define TEGRA210_SFC_RX_STATUS 0x0c +#define TEGRA210_SFC_RX_INT_STATUS 0x10 +#define TEGRA210_SFC_RX_INT_MASK 0x14 +#define TEGRA210_SFC_RX_INT_SET 0x18 +#define TEGRA210_SFC_RX_INT_CLEAR 0x1c +#define TEGRA210_SFC_RX_CIF_CTRL 0x20 +#define TEGRA210_SFC_RX_FREQ 0x24 + +/* + * SFC_TX registers are with respect to XBAR. + * The data goes out of SFC. + */ +#define TEGRA210_SFC_TX_STATUS 0x4c +#define TEGRA210_SFC_TX_INT_STATUS 0x50 +#define TEGRA210_SFC_TX_INT_MASK 0x54 +#define TEGRA210_SFC_TX_INT_SET 0x58 +#define TEGRA210_SFC_TX_INT_CLEAR 0x5c +#define TEGRA210_SFC_TX_CIF_CTRL 0x60 +#define TEGRA210_SFC_TX_FREQ 0x64 + +/* Register offsets from TEGRA210_SFC*_BASE */ +#define TEGRA210_SFC_ENABLE 0x80 +#define TEGRA210_SFC_SOFT_RESET 0x84 +#define TEGRA210_SFC_CG 0x88 +#define TEGRA210_SFC_STATUS 0x8c +#define TEGRA210_SFC_INT_STATUS 0x90 +#define TEGRA210_SFC_COEF_RAM 0xbc +#define TEGRA210_SFC_CFG_RAM_CTRL 0xc0 +#define TEGRA210_SFC_CFG_RAM_DATA 0xc4 + +/* Fields in TEGRA210_SFC_ENABLE */ +#define TEGRA210_SFC_EN_SHIFT 0 +#define TEGRA210_SFC_EN (1 << TEGRA210_SFC_EN_SHIFT) + +#define TEGRA210_SFC_NUM_RATES 12 + +/* Fields in TEGRA210_SFC_COEF_RAM */ +#define TEGRA210_SFC_COEF_RAM_EN BIT(0) + +#define TEGRA210_SFC_SOFT_RESET_EN BIT(0) + +/* Coefficients */ +#define TEGRA210_SFC_COEF_RAM_DEPTH 64 +#define TEGRA210_SFC_RAM_CTRL_RW_WRITE (1 << 14) +#define TEGRA210_SFC_RAM_CTRL_ADDR_INIT_EN (1 << 13) +#define TEGRA210_SFC_RAM_CTRL_SEQ_ACCESS_EN (1 << 12) + + +enum tegra210_sfc_path { + SFC_RX_PATH, + SFC_TX_PATH, + SFC_PATHS, +}; + +struct tegra210_sfc { + unsigned int mono_to_stereo[SFC_PATHS]; + unsigned int stereo_to_mono[SFC_PATHS]; + unsigned int srate_out; + unsigned int srate_in; + struct regmap *regmap; +}; + +#endif
The Audio Multiplexer (AMX) block can multiplex up to four input streams each of which can have maximum 16 channels and generate an output stream with maximum 16 channels. A byte RAM helps to form an output frame by any combination of bytes from the input frames.
This patch registers AMX driver with ASoC framework. The component driver exposes DAPM widgets, routes and kcontrols for the device. The DAI driver exposes AMX interfaces, which can be used to connect different components in the ASoC layer. Makefile and Kconfig support is added to allow build the driver. It can be enabled in the DT via "nvidia,tegra210-amx" for Tegra210 and Tegra186. For Tegra194 and later, "nvidia,tegra194-amx" can be used.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/Kconfig | 9 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra210_amx.c | 595 +++++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra210_amx.h | 93 +++++++ 4 files changed, 699 insertions(+) create mode 100644 sound/soc/tegra/tegra210_amx.c create mode 100644 sound/soc/tegra/tegra210_amx.h
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 102564e..54d8342 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -126,6 +126,15 @@ config SND_SOC_TEGRA210_SFC upto 2 channels (stereo). Say Y or M if you want to add support for Tegra210 SFC module.
+config SND_SOC_TEGRA210_AMX + tristate "Tegra210 AMX module" + help + Config to enable the Audio Multiplexer (AMX) which can multiplex + four input streams (each of up to 16 channels) and generate + output stream (of up to 16 channels). A byte RAM helps to form an + output frame by any combination of bytes from the input frames. + Say Y or M if you want to add support for Tegra210 AMX module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index bb0cf3a..549162b 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -15,6 +15,7 @@ snd-soc-tegra186-dspk-objs := tegra186_dspk.o snd-soc-tegra210-admaif-objs := tegra210_admaif.o snd-soc-tegra210-mvc-objs := tegra210_mvc.o snd-soc-tegra210-sfc-objs := tegra210_sfc.o +snd-soc-tegra210-amx-objs := tegra210_amx.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_TEGRA186_DSPK) += snd-soc-tegra186-dspk.o obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o +obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
# Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c new file mode 100644 index 0000000..a6aa4f5 --- /dev/null +++ b/sound/soc/tegra/tegra210_amx.c @@ -0,0 +1,595 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_amx.c - Tegra210 AMX driver +// +// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_amx.h" +#include "tegra_cif.h" + +/* + * The counter is in terms of AHUB clock cycles. If a frame is not + * received within these clock cycles, the AMX input channel gets + * automatically disabled. For now the counter is calculated as a + * function of sample rate (8 kHz) and AHUB clock (49.152 MHz). + * If later an accurate number is needed, the counter needs to be + * calculated at runtime. + * + * count = ahub_clk / sample_rate + */ +#define TEGRA194_MAX_FRAME_IDLE_COUNT 0x1800 + +#define AMX_CH_REG(id, reg) ((reg) + ((id) * TEGRA210_AMX_AUDIOCIF_CH_STRIDE)) + +static const struct reg_default tegra210_amx_reg_defaults[] = { + { TEGRA210_AMX_RX_INT_MASK, 0x0000000f}, + { TEGRA210_AMX_RX1_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX2_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX3_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_RX4_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_TX_INT_MASK, 0x00000001}, + { TEGRA210_AMX_TX_CIF_CTRL, 0x00007000}, + { TEGRA210_AMX_CG, 0x1}, + { TEGRA210_AMX_CFG_RAM_CTRL, 0x00004000}, +}; + +static void tegra210_amx_write_map_ram(struct tegra210_amx *amx) +{ + int i; + + regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_CTRL, + TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_AMX_RAM_DEPTH; i++) + regmap_write(amx->regmap, TEGRA210_AMX_CFG_RAM_DATA, + amx->map[i]); + + regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN0, amx->byte_mask[0]); + regmap_write(amx->regmap, TEGRA210_AMX_OUT_BYTE_EN1, amx->byte_mask[1]); +} + +static int tegra210_amx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + unsigned int val; + int err; + + /* Ensure if AMX is disabled */ + err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_STATUS, val, + !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to stop AMX, err = %d\n", err); + return err; + } + + /* SW reset */ + regmap_update_bits(amx->regmap, TEGRA210_AMX_SOFT_RESET, + TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK, + TEGRA210_AMX_SOFT_RESET_SOFT_EN); + + err = regmap_read_poll_timeout(amx->regmap, TEGRA210_AMX_SOFT_RESET, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to reset AMX, err = %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev) +{ + struct tegra210_amx *amx = dev_get_drvdata(dev); + + regcache_cache_only(amx->regmap, true); + regcache_mark_dirty(amx->regmap); + + return 0; +} + +static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev) +{ + struct tegra210_amx *amx = dev_get_drvdata(dev); + + regcache_cache_only(amx->regmap, false); + regcache_sync(amx->regmap); + + regmap_update_bits(amx->regmap, + TEGRA210_AMX_CTRL, + TEGRA210_AMX_CTRL_RX_DEP_MASK, + TEGRA210_AMX_WAIT_ON_ANY << TEGRA210_AMX_CTRL_RX_DEP_SHIFT); + + tegra210_amx_write_map_ram(amx); + + return 0; +} + +static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int reg) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + audio_bits = TEGRA_ACIF_BITS_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + + tegra_set_cif(amx->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); + + if (amx->soc_data->auto_disable) { + regmap_write(amx->regmap, + AMX_CH_REG(dai->id, TEGRA194_AMX_RX1_FRAME_PERIOD), + TEGRA194_MAX_FRAME_IDLE_COUNT); + regmap_write(amx->regmap, TEGRA210_AMX_CYA, 1); + } + + return tegra210_amx_set_audio_cif(dai, params, + AMX_CH_REG(dai->id, TEGRA210_AMX_RX1_CIF_CTRL)); +} + +static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_amx_set_audio_cif(dai, params, + TEGRA210_AMX_TX_CIF_CTRL); +} + +static int tegra210_amx_get_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); + unsigned char *bytes_map = (unsigned char *)&amx->map; + int reg = mc->reg; + int enabled; + + if (reg > 31) + enabled = amx->byte_mask[1] & (1 << (reg - 32)); + else + enabled = amx->byte_mask[0] & (1 << reg); + + if (enabled) + ucontrol->value.integer.value[0] = bytes_map[reg]; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_amx *amx = snd_soc_component_get_drvdata(cmpnt); + unsigned char *bytes_map = (unsigned char *)&amx->map; + int reg = mc->reg; + int value = ucontrol->value.integer.value[0]; + + if (value >= 0 && value <= 255) { + /* Update byte map and enable slot */ + bytes_map[reg] = value; + if (reg > 31) + amx->byte_mask[1] |= (1 << (reg - 32)); + else + amx->byte_mask[0] |= (1 << reg); + } else { + /* Reset byte map and disable slot */ + bytes_map[reg] = 0; + if (reg > 31) + amx->byte_mask[1] &= ~(1 << (reg - 32)); + else + amx->byte_mask[0] &= ~(1 << reg); + } + + return 0; +} + +static struct snd_soc_dai_ops tegra210_amx_out_dai_ops = { + .hw_params = tegra210_amx_out_hw_params, + .startup = tegra210_amx_startup, +}; + +static struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { + .hw_params = tegra210_amx_in_hw_params, +}; + +#define IN_DAI(id) \ + { \ + .name = "AMX-RX-CIF" #id, \ + .playback = { \ + .stream_name = "RX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "RX" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_amx_in_dai_ops, \ + } + +#define OUT_DAI \ + { \ + .name = "AMX-TX-CIF", \ + .playback = { \ + .stream_name = "TX-CIF-Playback", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "TX-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_amx_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_amx_dais[] = { + IN_DAI(1), + IN_DAI(2), + IN_DAI(3), + IN_DAI(4), + OUT_DAI, +}; + +static const struct snd_soc_dapm_widget tegra210_amx_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, TEGRA210_AMX_CTRL, 0, 0), + SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, TEGRA210_AMX_CTRL, 1, 0), + SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, TEGRA210_AMX_CTRL, 2, 0), + SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, TEGRA210_AMX_CTRL, 3, 0), + SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_AMX_ENABLE, + TEGRA210_AMX_ENABLE_SHIFT, 0), +}; + +#define STREAM_ROUTES(id, sname) \ + { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ + { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname },\ + { "RX" #id, NULL, "RX" #id "-CIF-" sname }, \ + { "TX", NULL, "RX" #id }, \ + { "TX-CIF-" sname, NULL, "TX" }, \ + { "XBAR-" sname, NULL, "TX-CIF-" sname }, \ + { "XBAR-RX", NULL, "XBAR-" sname } + +#define AMX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_amx_routes[] = { + AMX_ROUTES(1), + AMX_ROUTES(2), + AMX_ROUTES(3), + AMX_ROUTES(4), +}; + +#define TEGRA210_AMX_BYTE_MAP_CTRL(reg) \ + SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ + tegra210_amx_get_byte_map, \ + tegra210_amx_put_byte_map) + +static struct snd_kcontrol_new tegra210_amx_controls[] = { + TEGRA210_AMX_BYTE_MAP_CTRL(0), + TEGRA210_AMX_BYTE_MAP_CTRL(1), + TEGRA210_AMX_BYTE_MAP_CTRL(2), + TEGRA210_AMX_BYTE_MAP_CTRL(3), + TEGRA210_AMX_BYTE_MAP_CTRL(4), + TEGRA210_AMX_BYTE_MAP_CTRL(5), + TEGRA210_AMX_BYTE_MAP_CTRL(6), + TEGRA210_AMX_BYTE_MAP_CTRL(7), + TEGRA210_AMX_BYTE_MAP_CTRL(8), + TEGRA210_AMX_BYTE_MAP_CTRL(9), + TEGRA210_AMX_BYTE_MAP_CTRL(10), + TEGRA210_AMX_BYTE_MAP_CTRL(11), + TEGRA210_AMX_BYTE_MAP_CTRL(12), + TEGRA210_AMX_BYTE_MAP_CTRL(13), + TEGRA210_AMX_BYTE_MAP_CTRL(14), + TEGRA210_AMX_BYTE_MAP_CTRL(15), + TEGRA210_AMX_BYTE_MAP_CTRL(16), + TEGRA210_AMX_BYTE_MAP_CTRL(17), + TEGRA210_AMX_BYTE_MAP_CTRL(18), + TEGRA210_AMX_BYTE_MAP_CTRL(19), + TEGRA210_AMX_BYTE_MAP_CTRL(20), + TEGRA210_AMX_BYTE_MAP_CTRL(21), + TEGRA210_AMX_BYTE_MAP_CTRL(22), + TEGRA210_AMX_BYTE_MAP_CTRL(23), + TEGRA210_AMX_BYTE_MAP_CTRL(24), + TEGRA210_AMX_BYTE_MAP_CTRL(25), + TEGRA210_AMX_BYTE_MAP_CTRL(26), + TEGRA210_AMX_BYTE_MAP_CTRL(27), + TEGRA210_AMX_BYTE_MAP_CTRL(28), + TEGRA210_AMX_BYTE_MAP_CTRL(29), + TEGRA210_AMX_BYTE_MAP_CTRL(30), + TEGRA210_AMX_BYTE_MAP_CTRL(31), + TEGRA210_AMX_BYTE_MAP_CTRL(32), + TEGRA210_AMX_BYTE_MAP_CTRL(33), + TEGRA210_AMX_BYTE_MAP_CTRL(34), + TEGRA210_AMX_BYTE_MAP_CTRL(35), + TEGRA210_AMX_BYTE_MAP_CTRL(36), + TEGRA210_AMX_BYTE_MAP_CTRL(37), + TEGRA210_AMX_BYTE_MAP_CTRL(38), + TEGRA210_AMX_BYTE_MAP_CTRL(39), + TEGRA210_AMX_BYTE_MAP_CTRL(40), + TEGRA210_AMX_BYTE_MAP_CTRL(41), + TEGRA210_AMX_BYTE_MAP_CTRL(42), + TEGRA210_AMX_BYTE_MAP_CTRL(43), + TEGRA210_AMX_BYTE_MAP_CTRL(44), + TEGRA210_AMX_BYTE_MAP_CTRL(45), + TEGRA210_AMX_BYTE_MAP_CTRL(46), + TEGRA210_AMX_BYTE_MAP_CTRL(47), + TEGRA210_AMX_BYTE_MAP_CTRL(48), + TEGRA210_AMX_BYTE_MAP_CTRL(49), + TEGRA210_AMX_BYTE_MAP_CTRL(50), + TEGRA210_AMX_BYTE_MAP_CTRL(51), + TEGRA210_AMX_BYTE_MAP_CTRL(52), + TEGRA210_AMX_BYTE_MAP_CTRL(53), + TEGRA210_AMX_BYTE_MAP_CTRL(54), + TEGRA210_AMX_BYTE_MAP_CTRL(55), + TEGRA210_AMX_BYTE_MAP_CTRL(56), + TEGRA210_AMX_BYTE_MAP_CTRL(57), + TEGRA210_AMX_BYTE_MAP_CTRL(58), + TEGRA210_AMX_BYTE_MAP_CTRL(59), + TEGRA210_AMX_BYTE_MAP_CTRL(60), + TEGRA210_AMX_BYTE_MAP_CTRL(61), + TEGRA210_AMX_BYTE_MAP_CTRL(62), + TEGRA210_AMX_BYTE_MAP_CTRL(63), +}; + +static const struct snd_soc_component_driver tegra210_amx_cmpnt = { + .dapm_widgets = tegra210_amx_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), + .dapm_routes = tegra210_amx_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes), + .controls = tegra210_amx_controls, + .num_controls = ARRAY_SIZE(tegra210_amx_controls), +}; + +static bool tegra210_amx_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_INT_MASK ... TEGRA210_AMX_RX4_CIF_CTRL: + case TEGRA210_AMX_TX_INT_MASK ... TEGRA210_AMX_CG: + case TEGRA210_AMX_CTRL ... TEGRA210_AMX_CYA: + case TEGRA210_AMX_CFG_RAM_CTRL ... TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra194_amx_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: + return true; + default: + return tegra210_amx_wr_reg(dev, reg); + } +} + +static bool tegra210_amx_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_STATUS ... TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra194_amx_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA194_AMX_RX1_FRAME_PERIOD ... TEGRA194_AMX_RX4_FRAME_PERIOD: + return true; + default: + return tegra210_amx_rd_reg(dev, reg); + } +} + +static bool tegra210_amx_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TEGRA210_AMX_RX_STATUS: + case TEGRA210_AMX_RX_INT_STATUS: + case TEGRA210_AMX_RX_INT_SET: + case TEGRA210_AMX_TX_STATUS: + case TEGRA210_AMX_TX_INT_STATUS: + case TEGRA210_AMX_TX_INT_SET: + case TEGRA210_AMX_SOFT_RESET: + case TEGRA210_AMX_STATUS: + case TEGRA210_AMX_INT_STATUS: + case TEGRA210_AMX_CFG_RAM_CTRL: + case TEGRA210_AMX_CFG_RAM_DATA: + return true; + default: + break; + } + + return false; +} + +static const struct regmap_config tegra210_amx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_AMX_CFG_RAM_DATA, + .writeable_reg = tegra210_amx_wr_reg, + .readable_reg = tegra210_amx_rd_reg, + .volatile_reg = tegra210_amx_volatile_reg, + .reg_defaults = tegra210_amx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config tegra194_amx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA194_AMX_RX4_LAST_FRAME_PERIOD, + .writeable_reg = tegra194_amx_wr_reg, + .readable_reg = tegra194_amx_rd_reg, + .volatile_reg = tegra210_amx_volatile_reg, + .reg_defaults = tegra210_amx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_amx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct tegra210_amx_soc_data soc_data_tegra210 = { + .regmap_conf = &tegra210_amx_regmap_config, +}; + +static const struct tegra210_amx_soc_data soc_data_tegra194 = { + .regmap_conf = &tegra194_amx_regmap_config, + .auto_disable = true, +}; + +static const struct of_device_id tegra210_amx_of_match[] = { + { .compatible = "nvidia,tegra210-amx", .data = &soc_data_tegra210 }, + { .compatible = "nvidia,tegra194-amx", .data = &soc_data_tegra194 }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_amx_of_match); + +static int tegra210_amx_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_amx *amx; + void __iomem *regs; + int err; + const struct of_device_id *match; + struct tegra210_amx_soc_data *soc_data; + + match = of_match_device(tegra210_amx_of_match, dev); + + soc_data = (struct tegra210_amx_soc_data *)match->data; + + amx = devm_kzalloc(dev, sizeof(*amx), GFP_KERNEL); + if (!amx) + return -ENOMEM; + + amx->soc_data = soc_data; + + dev_set_drvdata(dev, amx); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + amx->regmap = devm_regmap_init_mmio(dev, regs, + soc_data->regmap_conf); + if (IS_ERR(amx->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(amx->regmap); + } + + regcache_cache_only(amx->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_amx_cmpnt, + tegra210_amx_dais, + ARRAY_SIZE(tegra210_amx_dais)); + if (err) { + dev_err(dev, "can't register AMX component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_amx_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_amx_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, + tegra210_amx_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_amx_driver = { + .driver = { + .name = "tegra210-amx", + .of_match_table = tegra210_amx_of_match, + .pm = &tegra210_amx_pm_ops, + }, + .probe = tegra210_amx_platform_probe, + .remove = tegra210_amx_platform_remove, +}; +module_platform_driver(tegra210_amx_driver); + +MODULE_AUTHOR("Songhee Baek sbaek@nvidia.com"); +MODULE_DESCRIPTION("Tegra210 AMX ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_amx.h b/sound/soc/tegra/tegra210_amx.h new file mode 100644 index 0000000..e277741 --- /dev/null +++ b/sound/soc/tegra/tegra210_amx.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_amx.h - Definitions for Tegra210 AMX driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_AMX_H__ +#define __TEGRA210_AMX_H__ + +/* Register offsets from TEGRA210_AMX*_BASE */ +#define TEGRA210_AMX_RX_STATUS 0x0c +#define TEGRA210_AMX_RX_INT_STATUS 0x10 +#define TEGRA210_AMX_RX_INT_MASK 0x14 +#define TEGRA210_AMX_RX_INT_SET 0x18 +#define TEGRA210_AMX_RX_INT_CLEAR 0x1c +#define TEGRA210_AMX_RX1_CIF_CTRL 0x20 +#define TEGRA210_AMX_RX2_CIF_CTRL 0x24 +#define TEGRA210_AMX_RX3_CIF_CTRL 0x28 +#define TEGRA210_AMX_RX4_CIF_CTRL 0x2c +#define TEGRA210_AMX_TX_STATUS 0x4c +#define TEGRA210_AMX_TX_INT_STATUS 0x50 +#define TEGRA210_AMX_TX_INT_MASK 0x54 +#define TEGRA210_AMX_TX_INT_SET 0x58 +#define TEGRA210_AMX_TX_INT_CLEAR 0x5c +#define TEGRA210_AMX_TX_CIF_CTRL 0x60 +#define TEGRA210_AMX_ENABLE 0x80 +#define TEGRA210_AMX_SOFT_RESET 0x84 +#define TEGRA210_AMX_CG 0x88 +#define TEGRA210_AMX_STATUS 0x8c +#define TEGRA210_AMX_INT_STATUS 0x90 +#define TEGRA210_AMX_CTRL 0xa4 +#define TEGRA210_AMX_OUT_BYTE_EN0 0xa8 +#define TEGRA210_AMX_OUT_BYTE_EN1 0xac +#define TEGRA210_AMX_CYA 0xb0 +#define TEGRA210_AMX_CFG_RAM_CTRL 0xb8 +#define TEGRA210_AMX_CFG_RAM_DATA 0xbc + +#define TEGRA194_AMX_RX1_FRAME_PERIOD 0xc0 +#define TEGRA194_AMX_RX4_FRAME_PERIOD 0xcc +#define TEGRA194_AMX_RX4_LAST_FRAME_PERIOD 0xdc + +/* Fields in TEGRA210_AMX_ENABLE */ +#define TEGRA210_AMX_ENABLE_SHIFT 0 + +/* Fields in TEGRA210_AMX_CTRL */ +#define TEGRA210_AMX_CTRL_MSTR_RX_NUM_SHIFT 14 +#define TEGRA210_AMX_CTRL_MSTR_RX_NUM_MASK (3 << TEGRA210_AMX_CTRL_MSTR_RX_NUM_SHIFT) + +#define TEGRA210_AMX_CTRL_RX_DEP_SHIFT 12 +#define TEGRA210_AMX_CTRL_RX_DEP_MASK (3 << TEGRA210_AMX_CTRL_RX_DEP_SHIFT) + +/* Fields in TEGRA210_AMX_CFG_RAM_CTRL */ +#define TEGRA210_AMX_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_AMX_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_AMX_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_AMX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_AMX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_AMX_CFG_CTRL_RAM_ADDR_SHIFT 0 + +/* Fields in TEGRA210_AMX_SOFT_RESET */ +#define TEGRA210_AMX_SOFT_RESET_SOFT_EN 1 +#define TEGRA210_AMX_SOFT_RESET_SOFT_RESET_MASK TEGRA210_AMX_SOFT_RESET_SOFT_EN + +#define TEGRA210_AMX_AUDIOCIF_CH_STRIDE 4 +#define TEGRA210_AMX_RAM_DEPTH 16 +#define TEGRA210_AMX_MAP_STREAM_NUM_SHIFT 6 +#define TEGRA210_AMX_MAP_WORD_NUM_SHIFT 2 +#define TEGRA210_AMX_MAP_BYTE_NUM_SHIFT 0 + +enum { + TEGRA210_AMX_WAIT_ON_ALL, + TEGRA210_AMX_WAIT_ON_ANY, +}; + +struct tegra210_amx_soc_data { + const struct regmap_config *regmap_conf; + bool auto_disable; +}; + +struct tegra210_amx { + const struct tegra210_amx_soc_data *soc_data; + unsigned int map[TEGRA210_AMX_RAM_DEPTH]; + struct regmap *regmap; + unsigned int byte_mask[2]; +}; + +#endif
The Audio Demultiplexer (ADX) block takes an input stream with up to 16 channels and demultiplexes it into four output streams of up to 16 channels each. A byte RAM helps to form output frames by any combination of bytes from the input frame. Its design is identical to that of byte RAM in the AMX except that the data flow direction is reversed.
This patch registers ADX driver with ASoC framework. The component driver exposes DAPM widgets, routes and kcontrols for the device. The DAI driver exposes ADX interfaces, which can be used to connect different components in the ASoC layer. Makefile and Kconfig support is added to allow build the driver. It can be enabled in the DT via "nvidia,tegra210-adx" compatible binding.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/Kconfig | 11 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra210_adx.c | 527 +++++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra210_adx.h | 72 ++++++ 4 files changed, 612 insertions(+) create mode 100644 sound/soc/tegra/tegra210_adx.c create mode 100644 sound/soc/tegra/tegra210_adx.h
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 54d8342..fd4a8d6 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -135,6 +135,17 @@ config SND_SOC_TEGRA210_AMX output frame by any combination of bytes from the input frames. Say Y or M if you want to add support for Tegra210 AMX module.
+config SND_SOC_TEGRA210_ADX + tristate "Tegra210 ADX module" + help + Config to enable the Audio Demultiplexer (ADX) which takes an + input stream (up to 16 channels) and demultiplexes it into four + output streams (each of up to 16 channels). A byte RAM helps to + form output frames by any combination of bytes from the input + frame. Its design is identical to that of byte RAM in the AMX + except that the data flow direction is reversed. + Say Y or M if you want to add support for Tegra210 ADX module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 549162b..8eb17ad 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -16,6 +16,7 @@ snd-soc-tegra210-admaif-objs := tegra210_admaif.o snd-soc-tegra210-mvc-objs := tegra210_mvc.o snd-soc-tegra210-sfc-objs := tegra210_sfc.o snd-soc-tegra210-amx-objs := tegra210_amx.o +snd-soc-tegra210-adx-objs := tegra210_adx.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_ADMAIF) += snd-soc-tegra210-admaif.o obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o +obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
# Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c new file mode 100644 index 0000000..5effafc --- /dev/null +++ b/sound/soc/tegra/tegra210_adx.c @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_adx.c - Tegra210 ADX driver +// +// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_adx.h" +#include "tegra_cif.h" + +static const struct reg_default tegra210_adx_reg_defaults[] = { + { TEGRA210_ADX_RX_INT_MASK, 0x00000001}, + { TEGRA210_ADX_RX_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX_INT_MASK, 0x0000000f }, + { TEGRA210_ADX_TX1_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX2_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX3_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_TX4_CIF_CTRL, 0x00007000}, + { TEGRA210_ADX_CG, 0x1}, + { TEGRA210_ADX_CFG_RAM_CTRL, 0x00004000}, +}; + +static void tegra210_adx_write_map_ram(struct tegra210_adx *adx) +{ + int i; + + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_CTRL, + TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN | + TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN | + TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE); + + for (i = 0; i < TEGRA210_ADX_RAM_DEPTH; i++) + regmap_write(adx->regmap, TEGRA210_ADX_CFG_RAM_DATA, + adx->map[i]); + + regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN0, adx->byte_mask[0]); + regmap_write(adx->regmap, TEGRA210_ADX_IN_BYTE_EN1, adx->byte_mask[1]); +} + +static int tegra210_adx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai); + unsigned int val; + int err; + + /* Ensure if ADX status is disabled */ + err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to stop ADX, err = %d\n", err); + return err; + } + + /* SW reset */ + regmap_update_bits(adx->regmap, TEGRA210_ADX_SOFT_RESET, + TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK, + TEGRA210_ADX_SOFT_RESET_SOFT_EN); + + err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_SOFT_RESET, + val, !(val & 0x1), 10, 10000); + if (err < 0) { + dev_err(dai->dev, "failed to reset ADX, err = %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev) +{ + struct tegra210_adx *adx = dev_get_drvdata(dev); + + regcache_cache_only(adx->regmap, true); + regcache_mark_dirty(adx->regmap); + + return 0; +} + +static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev) +{ + struct tegra210_adx *adx = dev_get_drvdata(dev); + + regcache_cache_only(adx->regmap, false); + regcache_sync(adx->regmap); + + tegra210_adx_write_map_ram(adx); + + return 0; +} + +static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, + unsigned int channels, + unsigned int format, + unsigned int reg) +{ + struct tegra210_adx *adx = snd_soc_dai_get_drvdata(dai); + struct tegra_cif_conf cif_conf; + int audio_bits; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + if (channels < 1 || channels > 16) + return -EINVAL; + + switch (format) { + case SNDRV_PCM_FORMAT_S8: + audio_bits = TEGRA_ACIF_BITS_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + + tegra_set_cif(adx->regmap, reg, &cif_conf); + + return 0; +} + +static int tegra210_adx_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_adx_set_audio_cif(dai, params_channels(params), + params_format(params), + TEGRA210_ADX_TX1_CIF_CTRL + ((dai->id - 1) * TEGRA210_ADX_AUDIOCIF_CH_STRIDE)); +} + +static int tegra210_adx_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return tegra210_adx_set_audio_cif(dai, params_channels(params), + params_format(params), + TEGRA210_ADX_RX_CIF_CTRL); +} + +static int tegra210_adx_get_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); + struct soc_mixer_control *mc; + unsigned char *bytes_map = (unsigned char *)&adx->map; + int enabled; + + mc = (struct soc_mixer_control *)kcontrol->private_value; + enabled = adx->byte_mask[mc->reg / 32] & (1 << (mc->reg % 32)); + + if (enabled) + ucontrol->value.integer.value[0] = bytes_map[mc->reg]; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_adx *adx = snd_soc_component_get_drvdata(cmpnt); + struct soc_mixer_control *mc; + unsigned char *bytes_map = (unsigned char *)&adx->map; + int value = ucontrol->value.integer.value[0]; + + mc = (struct soc_mixer_control *)kcontrol->private_value; + + if (value >= 0 && value <= 255) { + /* update byte map and enable slot */ + bytes_map[mc->reg] = value; + adx->byte_mask[mc->reg / 32] |= (1 << (mc->reg % 32)); + } else { + /* reset byte map and disable slot */ + bytes_map[mc->reg] = 0; + adx->byte_mask[mc->reg / 32] &= ~(1 << (mc->reg % 32)); + } + + return 0; +} + +static struct snd_soc_dai_ops tegra210_adx_in_dai_ops = { + .hw_params = tegra210_adx_in_hw_params, + .startup = tegra210_adx_startup, +}; + +static struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { + .hw_params = tegra210_adx_out_hw_params, +}; + +#define IN_DAI \ + { \ + .name = "ADX-RX-CIF", \ + .playback = { \ + .stream_name = "RX-CIF-Playback", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "RX-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_adx_in_dai_ops, \ + } + +#define OUT_DAI(id) \ + { \ + .name = "ADX-TX" #id "-CIF", \ + .playback = { \ + .stream_name = "TX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "TX" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 16, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_adx_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_adx_dais[] = { + IN_DAI, + OUT_DAI(1), + OUT_DAI(2), + OUT_DAI(3), + OUT_DAI(4), +}; + +static const struct snd_soc_dapm_widget tegra210_adx_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX", NULL, 0, TEGRA210_ADX_ENABLE, + TEGRA210_ADX_ENABLE_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_ADX_CTRL, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_ADX_CTRL, 1, 0), + SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_ADX_CTRL, 2, 0), + SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_ADX_CTRL, 3, 0), +}; + +#define STREAM_ROUTES(id, sname) \ + { "XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX" #id, NULL, "RX" }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } + +#define ADX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +#define STREAM_ROUTES(id, sname) \ + { "XBAR-" sname, NULL, "XBAR-TX" }, \ + { "RX-CIF-" sname, NULL, "XBAR-" sname }, \ + { "RX", NULL, "RX-CIF-" sname }, \ + { "TX" #id, NULL, "RX" }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } + +#define ADX_ROUTES(id) \ + STREAM_ROUTES(id, "Playback"), \ + STREAM_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_adx_routes[] = { + ADX_ROUTES(1), + ADX_ROUTES(2), + ADX_ROUTES(3), + ADX_ROUTES(4), +}; + +#define TEGRA210_ADX_BYTE_MAP_CTRL(reg) \ + SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 256, 0, \ + tegra210_adx_get_byte_map, \ + tegra210_adx_put_byte_map) + +static struct snd_kcontrol_new tegra210_adx_controls[] = { + TEGRA210_ADX_BYTE_MAP_CTRL(0), + TEGRA210_ADX_BYTE_MAP_CTRL(1), + TEGRA210_ADX_BYTE_MAP_CTRL(2), + TEGRA210_ADX_BYTE_MAP_CTRL(3), + TEGRA210_ADX_BYTE_MAP_CTRL(4), + TEGRA210_ADX_BYTE_MAP_CTRL(5), + TEGRA210_ADX_BYTE_MAP_CTRL(6), + TEGRA210_ADX_BYTE_MAP_CTRL(7), + TEGRA210_ADX_BYTE_MAP_CTRL(8), + TEGRA210_ADX_BYTE_MAP_CTRL(9), + TEGRA210_ADX_BYTE_MAP_CTRL(10), + TEGRA210_ADX_BYTE_MAP_CTRL(11), + TEGRA210_ADX_BYTE_MAP_CTRL(12), + TEGRA210_ADX_BYTE_MAP_CTRL(13), + TEGRA210_ADX_BYTE_MAP_CTRL(14), + TEGRA210_ADX_BYTE_MAP_CTRL(15), + TEGRA210_ADX_BYTE_MAP_CTRL(16), + TEGRA210_ADX_BYTE_MAP_CTRL(17), + TEGRA210_ADX_BYTE_MAP_CTRL(18), + TEGRA210_ADX_BYTE_MAP_CTRL(19), + TEGRA210_ADX_BYTE_MAP_CTRL(20), + TEGRA210_ADX_BYTE_MAP_CTRL(21), + TEGRA210_ADX_BYTE_MAP_CTRL(22), + TEGRA210_ADX_BYTE_MAP_CTRL(23), + TEGRA210_ADX_BYTE_MAP_CTRL(24), + TEGRA210_ADX_BYTE_MAP_CTRL(25), + TEGRA210_ADX_BYTE_MAP_CTRL(26), + TEGRA210_ADX_BYTE_MAP_CTRL(27), + TEGRA210_ADX_BYTE_MAP_CTRL(28), + TEGRA210_ADX_BYTE_MAP_CTRL(29), + TEGRA210_ADX_BYTE_MAP_CTRL(30), + TEGRA210_ADX_BYTE_MAP_CTRL(31), + TEGRA210_ADX_BYTE_MAP_CTRL(32), + TEGRA210_ADX_BYTE_MAP_CTRL(33), + TEGRA210_ADX_BYTE_MAP_CTRL(34), + TEGRA210_ADX_BYTE_MAP_CTRL(35), + TEGRA210_ADX_BYTE_MAP_CTRL(36), + TEGRA210_ADX_BYTE_MAP_CTRL(37), + TEGRA210_ADX_BYTE_MAP_CTRL(38), + TEGRA210_ADX_BYTE_MAP_CTRL(39), + TEGRA210_ADX_BYTE_MAP_CTRL(40), + TEGRA210_ADX_BYTE_MAP_CTRL(41), + TEGRA210_ADX_BYTE_MAP_CTRL(42), + TEGRA210_ADX_BYTE_MAP_CTRL(43), + TEGRA210_ADX_BYTE_MAP_CTRL(44), + TEGRA210_ADX_BYTE_MAP_CTRL(45), + TEGRA210_ADX_BYTE_MAP_CTRL(46), + TEGRA210_ADX_BYTE_MAP_CTRL(47), + TEGRA210_ADX_BYTE_MAP_CTRL(48), + TEGRA210_ADX_BYTE_MAP_CTRL(49), + TEGRA210_ADX_BYTE_MAP_CTRL(50), + TEGRA210_ADX_BYTE_MAP_CTRL(51), + TEGRA210_ADX_BYTE_MAP_CTRL(52), + TEGRA210_ADX_BYTE_MAP_CTRL(53), + TEGRA210_ADX_BYTE_MAP_CTRL(54), + TEGRA210_ADX_BYTE_MAP_CTRL(55), + TEGRA210_ADX_BYTE_MAP_CTRL(56), + TEGRA210_ADX_BYTE_MAP_CTRL(57), + TEGRA210_ADX_BYTE_MAP_CTRL(58), + TEGRA210_ADX_BYTE_MAP_CTRL(59), + TEGRA210_ADX_BYTE_MAP_CTRL(60), + TEGRA210_ADX_BYTE_MAP_CTRL(61), + TEGRA210_ADX_BYTE_MAP_CTRL(62), + TEGRA210_ADX_BYTE_MAP_CTRL(63), +}; + +static const struct snd_soc_component_driver tegra210_adx_cmpnt = { + .dapm_widgets = tegra210_adx_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_adx_widgets), + .dapm_routes = tegra210_adx_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_adx_routes), + .controls = tegra210_adx_controls, + .num_controls = ARRAY_SIZE(tegra210_adx_controls), +}; + +static bool tegra210_adx_wr_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_TX_INT_MASK ... TEGRA210_ADX_TX4_CIF_CTRL: + case TEGRA210_ADX_RX_INT_MASK ... TEGRA210_ADX_RX_CIF_CTRL: + case TEGRA210_ADX_ENABLE ... TEGRA210_ADX_CG: + case TEGRA210_ADX_CTRL ... TEGRA210_ADX_IN_BYTE_EN1: + case TEGRA210_ADX_CFG_RAM_CTRL ... TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_adx_rd_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS ... TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_adx_volatile_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_ADX_RX_STATUS: + case TEGRA210_ADX_RX_INT_STATUS: + case TEGRA210_ADX_RX_INT_SET: + case TEGRA210_ADX_TX_STATUS: + case TEGRA210_ADX_TX_INT_STATUS: + case TEGRA210_ADX_TX_INT_SET: + case TEGRA210_ADX_SOFT_RESET: + case TEGRA210_ADX_STATUS: + case TEGRA210_ADX_INT_STATUS: + case TEGRA210_ADX_CFG_RAM_CTRL: + case TEGRA210_ADX_CFG_RAM_DATA: + return true; + default: + break; + } + + return false; +} + +static const struct regmap_config tegra210_adx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_ADX_CFG_RAM_DATA, + .writeable_reg = tegra210_adx_wr_reg, + .readable_reg = tegra210_adx_rd_reg, + .volatile_reg = tegra210_adx_volatile_reg, + .reg_defaults = tegra210_adx_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_adx_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_adx_of_match[] = { + { .compatible = "nvidia,tegra210-adx" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_adx_of_match); + +static int tegra210_adx_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_adx *adx; + void __iomem *regs; + int err; + + adx = devm_kzalloc(dev, sizeof(*adx), GFP_KERNEL); + if (!adx) + return -ENOMEM; + + dev_set_drvdata(dev, adx); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + adx->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_adx_regmap_config); + if (IS_ERR(adx->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(adx->regmap); + } + + regcache_cache_only(adx->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_adx_cmpnt, + tegra210_adx_dais, + ARRAY_SIZE(tegra210_adx_dais)); + if (err) { + dev_err(dev, "can't register ADX component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_adx_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_adx_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, + tegra210_adx_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_adx_driver = { + .driver = { + .name = "tegra210-adx", + .of_match_table = tegra210_adx_of_match, + .pm = &tegra210_adx_pm_ops, + }, + .probe = tegra210_adx_platform_probe, + .remove = tegra210_adx_platform_remove, +}; +module_platform_driver(tegra210_adx_driver); + +MODULE_AUTHOR("Arun Shamanna Lakshmi aruns@nvidia.com"); +MODULE_DESCRIPTION("Tegra210 ADX ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_adx.h b/sound/soc/tegra/tegra210_adx.h new file mode 100644 index 0000000..d7dcb64 --- /dev/null +++ b/sound/soc/tegra/tegra210_adx.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_adx.h - Definitions for Tegra210 ADX driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_ADX_H__ +#define __TEGRA210_ADX_H__ + +/* Register offsets from TEGRA210_ADX*_BASE */ +#define TEGRA210_ADX_RX_STATUS 0x0c +#define TEGRA210_ADX_RX_INT_STATUS 0x10 +#define TEGRA210_ADX_RX_INT_MASK 0x14 +#define TEGRA210_ADX_RX_INT_SET 0x18 +#define TEGRA210_ADX_RX_INT_CLEAR 0x1c +#define TEGRA210_ADX_RX_CIF_CTRL 0x20 +#define TEGRA210_ADX_TX_STATUS 0x4c +#define TEGRA210_ADX_TX_INT_STATUS 0x50 +#define TEGRA210_ADX_TX_INT_MASK 0x54 +#define TEGRA210_ADX_TX_INT_SET 0x58 +#define TEGRA210_ADX_TX_INT_CLEAR 0x5c +#define TEGRA210_ADX_TX1_CIF_CTRL 0x60 +#define TEGRA210_ADX_TX2_CIF_CTRL 0x64 +#define TEGRA210_ADX_TX3_CIF_CTRL 0x68 +#define TEGRA210_ADX_TX4_CIF_CTRL 0x6c +#define TEGRA210_ADX_ENABLE 0x80 +#define TEGRA210_ADX_SOFT_RESET 0x84 +#define TEGRA210_ADX_CG 0x88 +#define TEGRA210_ADX_STATUS 0x8c +#define TEGRA210_ADX_INT_STATUS 0x90 +#define TEGRA210_ADX_CTRL 0xa4 +#define TEGRA210_ADX_IN_BYTE_EN0 0xa8 +#define TEGRA210_ADX_IN_BYTE_EN1 0xac +#define TEGRA210_ADX_CFG_RAM_CTRL 0xb8 +#define TEGRA210_ADX_CFG_RAM_DATA 0xbc + +/* Fields in TEGRA210_ADX_ENABLE */ +#define TEGRA210_ADX_ENABLE_SHIFT 0 + +/* Fields in TEGRA210_ADX_CFG_RAM_CTRL */ +#define TEGRA210_ADX_CFG_RAM_CTRL_RAM_ADDR_SHIFT 0 + +#define TEGRA210_ADX_CFG_RAM_CTRL_RW_SHIFT 14 +#define TEGRA210_ADX_CFG_RAM_CTRL_RW_WRITE (1 << TEGRA210_ADX_CFG_RAM_CTRL_RW_SHIFT) + +#define TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN (1 << TEGRA210_ADX_CFG_RAM_CTRL_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN (1 << TEGRA210_ADX_CFG_RAM_CTRL_SEQ_ACCESS_EN_SHIFT) + +/* Fields in TEGRA210_ADX_SOFT_RESET */ +#define TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT 0 +#define TEGRA210_ADX_SOFT_RESET_SOFT_RESET_MASK (1 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) +#define TEGRA210_ADX_SOFT_RESET_SOFT_EN (1 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) +#define TEGRA210_ADX_SOFT_RESET_SOFT_DEFAULT (0 << TEGRA210_ADX_SOFT_RESET_SOFT_RESET_SHIFT) + +#define TEGRA210_ADX_AUDIOCIF_CH_STRIDE 4 +#define TEGRA210_ADX_RAM_DEPTH 16 +#define TEGRA210_ADX_MAP_STREAM_NUMBER_SHIFT 6 +#define TEGRA210_ADX_MAP_WORD_NUMBER_SHIFT 2 +#define TEGRA210_ADX_MAP_BYTE_NUMBER_SHIFT 0 + +struct tegra210_adx { + struct regmap *regmap; + unsigned int map[TEGRA210_ADX_RAM_DEPTH]; + unsigned int byte_mask[2]; +}; + +#endif
The Mixer supports mixing of up to ten 7.1 audio input streams and generate five outputs (each of which can be any combination of the ten input streams)
This patch registers Mixer driver with ASoC framework. The component driver exposes DAPM widgets, routes and kcontrols for the device. The DAI driver exposes Mixer interfaces, which can be used to connect different components in the ASoC layer. Makefile and Kconfig support is added to allow build the driver. It can be enabled in the DT via "nvidia,tegra210-amixer" compatible binding.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- sound/soc/tegra/Kconfig | 10 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra210_mixer.c | 667 +++++++++++++++++++++++++++++++++++++++ sound/soc/tegra/tegra210_mixer.h | 100 ++++++ 4 files changed, 779 insertions(+) create mode 100644 sound/soc/tegra/tegra210_mixer.c create mode 100644 sound/soc/tegra/tegra210_mixer.h
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index fd4a8d6..cd45487 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -146,6 +146,16 @@ config SND_SOC_TEGRA210_ADX except that the data flow direction is reversed. Say Y or M if you want to add support for Tegra210 ADX module.
+config SND_SOC_TEGRA210_MIXER + tristate "Tegra210 Mixer module" + help + Config to enable the Mixer module which can help to mix multiple + audio streams. It supports mixing of upto 10 input streams, + where each stream can contain maximum of 8 channels. It supports + 5 output each of which can be a mix of any combination of 10 + input streams. + Say Y or M if you want to add support for Tegra210 Mixer module. + config SND_SOC_TEGRA_AUDIO_GRAPH_CARD tristate "Audio Graph Card based Tegra driver" depends on SND_AUDIO_GRAPH_CARD diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 8eb17ad..f19d566 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -17,6 +17,7 @@ snd-soc-tegra210-mvc-objs := tegra210_mvc.o snd-soc-tegra210-sfc-objs := tegra210_sfc.o snd-soc-tegra210-amx-objs := tegra210_amx.o snd-soc-tegra210-adx-objs := tegra210_adx.o +snd-soc-tegra210-mixer-objs := tegra210_mixer.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_MVC) += snd-soc-tegra210-mvc.o obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o +obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
# Tegra machine Support snd-soc-tegra-wm8903-objs := tegra_wm8903.o diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c new file mode 100644 index 0000000..54a0d38 --- /dev/null +++ b/sound/soc/tegra/tegra210_mixer.c @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// tegra210_mixer.c - Tegra210 MIXER driver +// +// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "tegra210_mixer.h" +#include "tegra_cif.h" + +#define MIXER_REG(reg, id) ((reg) + ((id) * TEGRA210_MIXER_REG_STRIDE)) +#define MIXER_REG_BASE(reg) ((reg) % TEGRA210_MIXER_REG_STRIDE) + +#define MIXER_GAIN_CFG_RAM_ADDR(id) \ + (TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 + \ + ((id) * TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE)) + +#define MIXER_RX_REG_DEFAULTS(id) \ + { MIXER_REG(TEGRA210_MIXER_RX1_CIF_CTRL, id), 0x00007700}, \ + { MIXER_REG(TEGRA210_MIXER_RX1_CTRL, id), 0x00010823}, \ + { MIXER_REG(TEGRA210_MIXER_RX1_PEAK_CTRL, id), 0x000012c0} + +#define MIXER_TX_REG_DEFAULTS(id) \ + { MIXER_REG(TEGRA210_MIXER_TX1_INT_MASK, (id)), 0x00000001}, \ + { MIXER_REG(TEGRA210_MIXER_TX1_CIF_CTRL, (id)), 0x00007700} + +#define REG_DURATION_PARAM(reg, i) ((reg) + NUM_GAIN_POLY_COEFFS + 1 + (i)) + +static const struct reg_default tegra210_mixer_reg_defaults[] = { + /* Inputs */ + MIXER_RX_REG_DEFAULTS(0), + MIXER_RX_REG_DEFAULTS(1), + MIXER_RX_REG_DEFAULTS(2), + MIXER_RX_REG_DEFAULTS(3), + MIXER_RX_REG_DEFAULTS(4), + MIXER_RX_REG_DEFAULTS(5), + MIXER_RX_REG_DEFAULTS(6), + MIXER_RX_REG_DEFAULTS(7), + MIXER_RX_REG_DEFAULTS(8), + MIXER_RX_REG_DEFAULTS(9), + /* Outputs */ + MIXER_TX_REG_DEFAULTS(0), + MIXER_TX_REG_DEFAULTS(1), + MIXER_TX_REG_DEFAULTS(2), + MIXER_TX_REG_DEFAULTS(3), + MIXER_TX_REG_DEFAULTS(4), + + { TEGRA210_MIXER_CG, 0x00000001}, + { TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000}, + { TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000}, + { TEGRA210_MIXER_ENABLE, 0x1 }, +}; + +/* Default gain parameters */ +static const struct tegra210_mixer_gain_params gain_params = { + /* Polynomial coefficients */ + { 0, 0, 0, 0, 0, 0, 0, 0x1000000, 0 }, + /* Gain value */ + 0x10000, + /* Duration Parameters */ + { 0, 0, 0x400, 0x8000000 }, +}; + +static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev) +{ + struct tegra210_mixer *mixer = dev_get_drvdata(dev); + + regcache_cache_only(mixer->regmap, true); + regcache_mark_dirty(mixer->regmap); + + return 0; +} + +static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev) +{ + struct tegra210_mixer *mixer = dev_get_drvdata(dev); + + regcache_cache_only(mixer->regmap, false); + regcache_sync(mixer->regmap); + + return 0; +} + +static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer, + unsigned int addr, + unsigned int coef) +{ + unsigned int reg, val; + int err; + + /* Check if busy */ + err = regmap_read_poll_timeout(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, + val, !(val & 0x80000000), 10, 10000); + if (err < 0) + return err; + + reg = (addr << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) & + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE; + reg |= TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN; + + regmap_write(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, + reg); + regmap_write(mixer->regmap, + TEGRA210_MIXER_GAIN_CFG_RAM_DATA, + coef); + + return 0; +} + +static int tegra210_mixer_configure_gain(struct snd_soc_component *cmpnt, + unsigned int id, bool instant_gain) +{ + struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = MIXER_GAIN_CFG_RAM_ADDR(id); + int err, i; + + pm_runtime_get_sync(cmpnt->dev); + + /* Write default gain poly coefficients */ + for (i = 0; i < NUM_GAIN_POLY_COEFFS; i++) { + err = tegra210_mixer_write_ram(mixer, reg + i, + gain_params.poly_coeff[i]); + + if (err < 0) + goto rpm_put; + } + + /* Write stored gain value */ + err = tegra210_mixer_write_ram(mixer, reg + NUM_GAIN_POLY_COEFFS, + mixer->gain_value[id]); + if (err < 0) + goto rpm_put; + + /* Write duration parameters */ + for (i = 0; i < NUM_DURATION_PARMS; i++) { + int val; + + if (instant_gain) + val = 1; + else + val = gain_params.duration[i]; + + err = tegra210_mixer_write_ram(mixer, + REG_DURATION_PARAM(reg, i), + val); + if (err < 0) + goto rpm_put; + } + + /* Trigger to apply gain configurations */ + err = tegra210_mixer_write_ram(mixer, reg + REG_CFG_DONE_TRIGGER, + VAL_CFG_DONE_TRIGGER); + +rpm_put: + pm_runtime_put(cmpnt->dev); + + return err; +} + +static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg; + unsigned int i; + + i = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) / + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE; + + ucontrol->value.integer.value[0] = mixer->gain_value[i]; + + return 0; +} + +static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt); + unsigned int reg = mc->reg, id; + bool instant_gain = false; + + if (strstr(kcontrol->id.name, "Instant Gain Volume")) + instant_gain = true; + + /* Save gain value for specific MIXER input */ + id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) / + TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE; + + mixer->gain_value[id] = ucontrol->value.integer.value[0]; + + return tegra210_mixer_configure_gain(cmpnt, id, instant_gain); +} + +static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, + struct snd_pcm_hw_params *params, + unsigned int reg, + unsigned int id) +{ + unsigned int channels, audio_bits; + struct tegra_cif_conf cif_conf; + + memset(&cif_conf, 0, sizeof(struct tegra_cif_conf)); + + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + audio_bits = TEGRA_ACIF_BITS_16; + break; + case SNDRV_PCM_FORMAT_S32_LE: + audio_bits = TEGRA_ACIF_BITS_32; + break; + default: + return -EINVAL; + } + + cif_conf.audio_ch = channels; + cif_conf.client_ch = channels; + cif_conf.audio_bits = audio_bits; + cif_conf.client_bits = audio_bits; + + tegra_set_cif(mixer->regmap, + reg + (id * TEGRA210_MIXER_REG_STRIDE), + &cif_conf); + + return 0; +} + +static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai); + int err; + + err = tegra210_mixer_set_audio_cif(mixer, params, + TEGRA210_MIXER_RX1_CIF_CTRL, + dai->id); + if (err < 0) + return err; + + return tegra210_mixer_configure_gain(dai->component, dai->id, false); +} + +static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tegra210_mixer *mixer = snd_soc_dai_get_drvdata(dai); + + return tegra210_mixer_set_audio_cif(mixer, params, + TEGRA210_MIXER_TX1_CIF_CTRL, + dai->id - TEGRA210_MIXER_RX_MAX); +} + +static struct snd_soc_dai_ops tegra210_mixer_out_dai_ops = { + .hw_params = tegra210_mixer_out_hw_params, +}; + +static struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { + .hw_params = tegra210_mixer_in_hw_params, +}; + +#define IN_DAI(id) \ + { \ + .name = "MIXER-RX-CIF"#id, \ + .playback = { \ + .stream_name = "RX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 8, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "RX" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 8, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_mixer_in_dai_ops, \ + } + +#define OUT_DAI(id) \ + { \ + .name = "MIXER-TX-CIF" #id, \ + .playback = { \ + .stream_name = "TX" #id "-CIF-Playback",\ + .channels_min = 1, \ + .channels_max = 8, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .capture = { \ + .stream_name = "TX" #id "-CIF-Capture", \ + .channels_min = 1, \ + .channels_max = 8, \ + .rates = SNDRV_PCM_RATE_8000_192000, \ + .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + }, \ + .ops = &tegra210_mixer_out_dai_ops, \ + } + +static struct snd_soc_dai_driver tegra210_mixer_dais[] = { + /* Mixer Input */ + IN_DAI(1), + IN_DAI(2), + IN_DAI(3), + IN_DAI(4), + IN_DAI(5), + IN_DAI(6), + IN_DAI(7), + IN_DAI(8), + IN_DAI(9), + IN_DAI(10), + + /* Mixer Output */ + OUT_DAI(1), + OUT_DAI(2), + OUT_DAI(3), + OUT_DAI(4), + OUT_DAI(5), +}; + +#define ADDER_CTRL_DECL(name, reg) \ + static const struct snd_kcontrol_new name[] = { \ + SOC_DAPM_SINGLE("RX1", reg, 0, 1, 0), \ + SOC_DAPM_SINGLE("RX2", reg, 1, 1, 0), \ + SOC_DAPM_SINGLE("RX3", reg, 2, 1, 0), \ + SOC_DAPM_SINGLE("RX4", reg, 3, 1, 0), \ + SOC_DAPM_SINGLE("RX5", reg, 4, 1, 0), \ + SOC_DAPM_SINGLE("RX6", reg, 5, 1, 0), \ + SOC_DAPM_SINGLE("RX7", reg, 6, 1, 0), \ + SOC_DAPM_SINGLE("RX8", reg, 7, 1, 0), \ + SOC_DAPM_SINGLE("RX9", reg, 8, 1, 0), \ + SOC_DAPM_SINGLE("RX10", reg, 9, 1, 0), \ + } + +ADDER_CTRL_DECL(adder1, TEGRA210_MIXER_TX1_ADDER_CONFIG); +ADDER_CTRL_DECL(adder2, TEGRA210_MIXER_TX2_ADDER_CONFIG); +ADDER_CTRL_DECL(adder3, TEGRA210_MIXER_TX3_ADDER_CONFIG); +ADDER_CTRL_DECL(adder4, TEGRA210_MIXER_TX4_ADDER_CONFIG); +ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG); + +#define GAIN_CTRL(id) \ + SOC_SINGLE_EXT("RX" #id " Gain Volume", \ + MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \ + 0x20000, 0, tegra210_mixer_get_gain, \ + tegra210_mixer_put_gain), \ + SOC_SINGLE_EXT("RX" #id " Instant Gain Volume", \ + MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0, \ + 0x20000, 0, tegra210_mixer_get_gain, \ + tegra210_mixer_put_gain), + +/* Volume controls for all MIXER inputs */ +static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = { + GAIN_CTRL(1) + GAIN_CTRL(2) + GAIN_CTRL(3) + GAIN_CTRL(4) + GAIN_CTRL(5) + GAIN_CTRL(6) + GAIN_CTRL(7) + GAIN_CTRL(8) + GAIN_CTRL(9) + GAIN_CTRL(10) +}; + +static const struct snd_soc_dapm_widget tegra210_mixer_widgets[] = { + SND_SOC_DAPM_AIF_IN("RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX4", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX5", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX6", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX7", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX8", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX9", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX10", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX1", NULL, 0, TEGRA210_MIXER_TX1_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX2", NULL, 0, TEGRA210_MIXER_TX2_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX3", NULL, 0, TEGRA210_MIXER_TX3_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX4", NULL, 0, TEGRA210_MIXER_TX4_ENABLE, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX5", NULL, 0, TEGRA210_MIXER_TX5_ENABLE, 0, 0), + SND_SOC_DAPM_MIXER("Adder1", SND_SOC_NOPM, 1, 0, adder1, + ARRAY_SIZE(adder1)), + SND_SOC_DAPM_MIXER("Adder2", SND_SOC_NOPM, 1, 0, adder2, + ARRAY_SIZE(adder2)), + SND_SOC_DAPM_MIXER("Adder3", SND_SOC_NOPM, 1, 0, adder3, + ARRAY_SIZE(adder3)), + SND_SOC_DAPM_MIXER("Adder4", SND_SOC_NOPM, 1, 0, adder4, + ARRAY_SIZE(adder4)), + SND_SOC_DAPM_MIXER("Adder5", SND_SOC_NOPM, 1, 0, adder5, + ARRAY_SIZE(adder5)), +}; + +#define RX_ROUTES(id, sname) \ + { "RX" #id " XBAR-" sname, NULL, "RX" #id " XBAR-TX" }, \ + { "RX" #id "-CIF-" sname, NULL, "RX" #id " XBAR-" sname }, \ + { "RX" #id, NULL, "RX" #id "-CIF-" sname } + +#define MIXER_RX_ROUTES(id) \ + RX_ROUTES(id, "Playback"), \ + RX_ROUTES(id, "Capture") + +#define ADDER_ROUTES(id, sname) \ + { "Adder" #id, "RX1", "RX1" }, \ + { "Adder" #id, "RX2", "RX2" }, \ + { "Adder" #id, "RX3", "RX3" }, \ + { "Adder" #id, "RX4", "RX4" }, \ + { "Adder" #id, "RX5", "RX5" }, \ + { "Adder" #id, "RX6", "RX6" }, \ + { "Adder" #id, "RX7", "RX7" }, \ + { "Adder" #id, "RX8", "RX8" }, \ + { "Adder" #id, "RX9", "RX9" }, \ + { "Adder" #id, "RX10", "RX10" }, \ + { "TX" #id, NULL, "Adder" #id }, \ + { "TX" #id "-CIF-" sname, NULL, "TX" #id }, \ + { "TX" #id " XBAR-" sname, NULL, "TX" #id "-CIF-" sname }, \ + { "TX" #id " XBAR-RX", NULL, "TX" #id " XBAR-" sname } \ + +#define TX_ROUTES(id, sname) \ + ADDER_ROUTES(1, sname), \ + ADDER_ROUTES(2, sname), \ + ADDER_ROUTES(3, sname), \ + ADDER_ROUTES(4, sname), \ + ADDER_ROUTES(5, sname) + +#define MIXER_TX_ROUTES(id) \ + TX_ROUTES(id, "Playback"), \ + TX_ROUTES(id, "Capture") + +static const struct snd_soc_dapm_route tegra210_mixer_routes[] = { + /* Input */ + MIXER_RX_ROUTES(1), + MIXER_RX_ROUTES(2), + MIXER_RX_ROUTES(3), + MIXER_RX_ROUTES(4), + MIXER_RX_ROUTES(5), + MIXER_RX_ROUTES(6), + MIXER_RX_ROUTES(7), + MIXER_RX_ROUTES(8), + MIXER_RX_ROUTES(9), + MIXER_RX_ROUTES(10), + /* Output */ + MIXER_TX_ROUTES(1), + MIXER_TX_ROUTES(2), + MIXER_TX_ROUTES(3), + MIXER_TX_ROUTES(4), + MIXER_TX_ROUTES(5), +}; + +static const struct snd_soc_component_driver tegra210_mixer_cmpnt = { + .dapm_widgets = tegra210_mixer_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra210_mixer_widgets), + .dapm_routes = tegra210_mixer_routes, + .num_dapm_routes = ARRAY_SIZE(tegra210_mixer_routes), + .controls = tegra210_mixer_gain_ctls, + .num_controls = ARRAY_SIZE(tegra210_mixer_gain_ctls), +}; + +static bool tegra210_mixer_wr_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET: + case TEGRA210_MIXER_RX1_CIF_CTRL ... TEGRA210_MIXER_RX1_PEAK_CTRL: + + case TEGRA210_MIXER_TX1_ENABLE: + case TEGRA210_MIXER_TX1_SOFT_RESET: + case TEGRA210_MIXER_TX1_INT_MASK ... TEGRA210_MIXER_TX1_ADDER_CONFIG: + + case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CG: + case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL ... TEGRA210_MIXER_CTRL: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_rd_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET ... TEGRA210_MIXER_RX1_SAMPLE_COUNT: + case TEGRA210_MIXER_TX1_ENABLE ... TEGRA210_MIXER_TX1_ADDER_CONFIG: + case TEGRA210_MIXER_ENABLE ... TEGRA210_MIXER_CTRL: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_volatile_reg(struct device *dev, + unsigned int reg) +{ + if (reg < TEGRA210_MIXER_RX_LIMIT) + reg = MIXER_REG_BASE(reg); + else if (reg < TEGRA210_MIXER_TX_LIMIT) + reg = MIXER_REG_BASE(reg) + TEGRA210_MIXER_TX1_ENABLE; + + switch (reg) { + case TEGRA210_MIXER_RX1_SOFT_RESET: + case TEGRA210_MIXER_RX1_STATUS: + + case TEGRA210_MIXER_TX1_SOFT_RESET: + case TEGRA210_MIXER_TX1_STATUS: + case TEGRA210_MIXER_TX1_INT_STATUS: + case TEGRA210_MIXER_TX1_INT_SET: + + case TEGRA210_MIXER_SOFT_RESET: + case TEGRA210_MIXER_STATUS: + case TEGRA210_MIXER_INT_STATUS: + case TEGRA210_MIXER_GAIN_CFG_RAM_CTRL: + case TEGRA210_MIXER_GAIN_CFG_RAM_DATA: + case TEGRA210_MIXER_PEAKM_RAM_CTRL: + case TEGRA210_MIXER_PEAKM_RAM_DATA: + return true; + default: + return false; + } +} + +static bool tegra210_mixer_precious_reg(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case TEGRA210_MIXER_GAIN_CFG_RAM_DATA: + case TEGRA210_MIXER_PEAKM_RAM_DATA: + return true; + default: + return false; + } +} + +static const struct regmap_config tegra210_mixer_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = TEGRA210_MIXER_CTRL, + .writeable_reg = tegra210_mixer_wr_reg, + .readable_reg = tegra210_mixer_rd_reg, + .volatile_reg = tegra210_mixer_volatile_reg, + .precious_reg = tegra210_mixer_precious_reg, + .reg_defaults = tegra210_mixer_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(tegra210_mixer_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static const struct of_device_id tegra210_mixer_of_match[] = { + { .compatible = "nvidia,tegra210-amixer" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra210_mixer_of_match); + +static int tegra210_mixer_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra210_mixer *mixer; + void __iomem *regs; + int err, i; + + mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + + dev_set_drvdata(dev, mixer); + + /* Use default gain value for all MIXER inputs */ + for (i = 0; i < TEGRA210_MIXER_RX_MAX; i++) + mixer->gain_value[i] = gain_params.gain_value; + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + mixer->regmap = devm_regmap_init_mmio(dev, regs, + &tegra210_mixer_regmap_config); + if (IS_ERR(mixer->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(mixer->regmap); + } + + regcache_cache_only(mixer->regmap, true); + + err = devm_snd_soc_register_component(dev, &tegra210_mixer_cmpnt, + tegra210_mixer_dais, + ARRAY_SIZE(tegra210_mixer_dais)); + if (err) { + dev_err(dev, "can't register MIXER component, err: %d\n", err); + return err; + } + + pm_runtime_enable(dev); + + return 0; +} + +static int tegra210_mixer_platform_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops tegra210_mixer_pm_ops = { + SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend, + tegra210_mixer_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver tegra210_mixer_driver = { + .driver = { + .name = "tegra210_mixer", + .of_match_table = tegra210_mixer_of_match, + .pm = &tegra210_mixer_pm_ops, + }, + .probe = tegra210_mixer_platform_probe, + .remove = tegra210_mixer_platform_remove, +}; +module_platform_driver(tegra210_mixer_driver); + +MODULE_AUTHOR("Arun Shamanna Lakshmi aruns@nvidia.com"); +MODULE_DESCRIPTION("Tegra210 MIXER ASoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/tegra/tegra210_mixer.h b/sound/soc/tegra/tegra210_mixer.h new file mode 100644 index 0000000..a330530 --- /dev/null +++ b/sound/soc/tegra/tegra210_mixer.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tegra210_mixer.h - Definitions for Tegra210 MIXER driver + * + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + */ + +#ifndef __TEGRA210_MIXER_H__ +#define __TEGRA210_MIXER_H__ + +/* XBAR_RX related MIXER offsets */ +#define TEGRA210_MIXER_RX1_SOFT_RESET 0x04 +#define TEGRA210_MIXER_RX1_STATUS 0x10 +#define TEGRA210_MIXER_RX1_CIF_CTRL 0x24 +#define TEGRA210_MIXER_RX1_CTRL 0x28 +#define TEGRA210_MIXER_RX1_PEAK_CTRL 0x2c +#define TEGRA210_MIXER_RX1_SAMPLE_COUNT 0x30 + +/* XBAR_TX related MIXER offsets */ +#define TEGRA210_MIXER_TX1_ENABLE 0x280 +#define TEGRA210_MIXER_TX1_SOFT_RESET 0x284 +#define TEGRA210_MIXER_TX1_STATUS 0x290 +#define TEGRA210_MIXER_TX1_INT_STATUS 0x294 +#define TEGRA210_MIXER_TX1_INT_MASK 0x298 +#define TEGRA210_MIXER_TX1_INT_SET 0x29c +#define TEGRA210_MIXER_TX1_INT_CLEAR 0x2a0 +#define TEGRA210_MIXER_TX1_CIF_CTRL 0x2a4 +#define TEGRA210_MIXER_TX1_ADDER_CONFIG 0x2a8 + +/* MIXER related offsets */ +#define TEGRA210_MIXER_ENABLE 0x400 +#define TEGRA210_MIXER_SOFT_RESET 0x404 +#define TEGRA210_MIXER_CG 0x408 +#define TEGRA210_MIXER_STATUS 0x410 +#define TEGRA210_MIXER_INT_STATUS 0x414 +#define TEGRA210_MIXER_GAIN_CFG_RAM_CTRL 0x42c +#define TEGRA210_MIXER_GAIN_CFG_RAM_DATA 0x430 +#define TEGRA210_MIXER_PEAKM_RAM_CTRL 0x434 +#define TEGRA210_MIXER_PEAKM_RAM_DATA 0x438 +#define TEGRA210_MIXER_CTRL 0x43c + +#define TEGRA210_MIXER_TX2_ADDER_CONFIG (TEGRA210_MIXER_TX1_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX3_ADDER_CONFIG (TEGRA210_MIXER_TX2_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX4_ADDER_CONFIG (TEGRA210_MIXER_TX3_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX5_ADDER_CONFIG (TEGRA210_MIXER_TX4_ADDER_CONFIG + TEGRA210_MIXER_REG_STRIDE) + +#define TEGRA210_MIXER_TX2_ENABLE (TEGRA210_MIXER_TX1_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX3_ENABLE (TEGRA210_MIXER_TX2_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX4_ENABLE (TEGRA210_MIXER_TX3_ENABLE + TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX5_ENABLE (TEGRA210_MIXER_TX4_ENABLE + TEGRA210_MIXER_REG_STRIDE) + +/* Fields in TEGRA210_MIXER_ENABLE */ +#define TEGRA210_MIXER_ENABLE_SHIFT 0 +#define TEGRA210_MIXER_ENABLE_MASK (1 << TEGRA210_MIXER_ENABLE_SHIFT) +#define TEGRA210_MIXER_EN (1 << TEGRA210_MIXER_ENABLE_SHIFT) + +/* Fields in TEGRA210_MIXER_GAIN_CFG_RAM_CTRL */ +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0 0x0 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE 0x10 + +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT 14 +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_RW_WRITE (1 << TEGRA210_MIXER_GAIN_CFG_RAM_RW_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT 13 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN (1 << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_INIT_EN_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT 12 +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_MASK (1 << TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT) +#define TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN (1 << TEGRA210_MIXER_GAIN_CFG_RAM_SEQ_ACCESS_EN_SHIFT) + +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT 0 +#define TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_MASK (0x1ff << TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_SHIFT) + +#define TEGRA210_MIXER_REG_STRIDE 0x40 +#define TEGRA210_MIXER_RX_MAX 10 +#define TEGRA210_MIXER_RX_LIMIT (TEGRA210_MIXER_RX_MAX * TEGRA210_MIXER_REG_STRIDE) +#define TEGRA210_MIXER_TX_MAX 5 +#define TEGRA210_MIXER_TX_LIMIT (TEGRA210_MIXER_RX_LIMIT + (TEGRA210_MIXER_TX_MAX * TEGRA210_MIXER_REG_STRIDE)) + +#define REG_CFG_DONE_TRIGGER 0xf +#define VAL_CFG_DONE_TRIGGER 0x1 + +#define NUM_GAIN_POLY_COEFFS 9 +#define NUM_DURATION_PARMS 4 + +struct tegra210_mixer_gain_params { + int poly_coeff[NUM_GAIN_POLY_COEFFS]; + int gain_value; + int duration[NUM_DURATION_PARMS]; +}; + +struct tegra210_mixer { + int gain_value[TEGRA210_MIXER_RX_MAX]; + struct regmap *regmap; +}; + +#endif
Enable configs for following modules: * SFC (Sampling Frequency Converter) * MVC (Master Volume Control) * AMX (Audio Multiplexer) * ADX (Audio Demultiplexer) * Mixer
These configs are used on Tegra186 and later SoCs as well.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- arch/arm64/configs/defconfig | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 3bf6f8a..b936a23 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -773,6 +773,11 @@ CONFIG_SND_SOC_TEGRA210_DMIC=m CONFIG_SND_SOC_TEGRA210_I2S=m CONFIG_SND_SOC_TEGRA186_DSPK=m CONFIG_SND_SOC_TEGRA210_ADMAIF=m +CONFIG_SND_SOC_TEGRA210_MVC=m +CONFIG_SND_SOC_TEGRA210_SFC=m +CONFIG_SND_SOC_TEGRA210_AMX=m +CONFIG_SND_SOC_TEGRA210_ADX=m +CONFIG_SND_SOC_TEGRA210_MIXER=m CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_ES7134=m
Add DT nodes for following AHUB devices: * SFC (Sampling Frequency Converter) * MVC (Master Volume Control) * AMX (Audio Multiplexer) * ADX (Audio Demultiplexer) * Mixer
Above devices are added for Tegra210, Tegra186 and Tegra194 generations of Tegra SoC.
Signed-off-by: Sameer Pujar spujar@nvidia.com --- arch/arm64/boot/dts/nvidia/tegra186.dtsi | 120 +++++++++++++++++++++++++++++++ arch/arm64/boot/dts/nvidia/tegra194.dtsi | 116 ++++++++++++++++++++++++++++++ arch/arm64/boot/dts/nvidia/tegra210.dtsi | 77 ++++++++++++++++++++ 3 files changed, 313 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi index e94f8ad..0d0ada5 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi @@ -354,6 +354,126 @@ sound-name-prefix = "DSPK2"; status = "disabled"; }; + + tegra_sfc1: sfc@2902000 { + compatible = "nvidia,tegra186-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902000 0x200>; + sound-name-prefix = "SFC1"; + status = "disabled"; + }; + + tegra_sfc2: sfc@2902200 { + compatible = "nvidia,tegra186-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902200 0x200>; + sound-name-prefix = "SFC2"; + status = "disabled"; + }; + + tegra_sfc3: sfc@2902400 { + compatible = "nvidia,tegra186-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902400 0x200>; + sound-name-prefix = "SFC3"; + status = "disabled"; + }; + + tegra_sfc4: sfc@2902600 { + compatible = "nvidia,tegra186-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902600 0x200>; + sound-name-prefix = "SFC4"; + status = "disabled"; + }; + + tegra_mvc1: mvc@290a000 { + compatible = "nvidia,tegra186-mvc", + "nvidia,tegra210-mvc"; + reg = <0x290a000 0x200>; + sound-name-prefix = "MVC1"; + status = "disabled"; + }; + + tegra_mvc2: mvc@290a200 { + compatible = "nvidia,tegra186-mvc", + "nvidia,tegra210-mvc"; + reg = <0x290a200 0x200>; + sound-name-prefix = "MVC2"; + status = "disabled"; + }; + + tegra_amx1: amx@2903000 { + compatible = "nvidia,tegra186-amx", + "nvidia,tegra210-amx"; + reg = <0x2903000 0x100>; + sound-name-prefix = "AMX1"; + status = "disabled"; + }; + + tegra_amx2: amx@2903100 { + compatible = "nvidia,tegra186-amx", + "nvidia,tegra210-amx"; + reg = <0x2903100 0x100>; + sound-name-prefix = "AMX2"; + status = "disabled"; + }; + + tegra_amx3: amx@2903200 { + compatible = "nvidia,tegra186-amx", + "nvidia,tegra210-amx"; + reg = <0x2903200 0x100>; + sound-name-prefix = "AMX3"; + status = "disabled"; + }; + + tegra_amx4: amx@2903300 { + compatible = "nvidia,tegra186-amx", + "nvidia,tegra210-amx"; + reg = <0x2903300 0x100>; + sound-name-prefix = "AMX4"; + status = "disabled"; + }; + + tegra_adx1: adx@2903800 { + compatible = "nvidia,tegra186-adx", + "nvidia,tegra210-adx"; + reg = <0x2903800 0x100>; + sound-name-prefix = "ADX1"; + status = "disabled"; + }; + + tegra_adx2: adx@2903900 { + compatible = "nvidia,tegra186-adx", + "nvidia,tegra210-adx"; + reg = <0x2903900 0x100>; + sound-name-prefix = "ADX2"; + status = "disabled"; + }; + + tegra_adx3: adx@2903a00 { + compatible = "nvidia,tegra186-adx", + "nvidia,tegra210-adx"; + reg = <0x2903a00 0x100>; + sound-name-prefix = "ADX3"; + status = "disabled"; + }; + + tegra_adx4: adx@2903b00 { + compatible = "nvidia,tegra186-adx", + "nvidia,tegra210-adx"; + reg = <0x2903b00 0x100>; + sound-name-prefix = "ADX4"; + status = "disabled"; + }; + + tegra_amixer: amixer@290bb00 { + compatible = "nvidia,tegra186-amixer", + "nvidia,tegra210-amixer"; + reg = <0x290bb00 0x800>; + sound-name-prefix = "MIXER"; + status = "disabled"; + }; }; };
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi index c8250a3..6027d84 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi @@ -363,6 +363,122 @@ sound-name-prefix = "DSPK2"; status = "disabled"; }; + + tegra_sfc1: sfc@2902000 { + compatible = "nvidia,tegra194-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902000 0x200>; + sound-name-prefix = "SFC1"; + status = "disabled"; + }; + + tegra_sfc2: sfc@2902200 { + compatible = "nvidia,tegra194-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902200 0x200>; + sound-name-prefix = "SFC2"; + status = "disabled"; + }; + + tegra_sfc3: sfc@2902400 { + compatible = "nvidia,tegra194-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902400 0x200>; + sound-name-prefix = "SFC3"; + status = "disabled"; + }; + + tegra_sfc4: sfc@2902600 { + compatible = "nvidia,tegra194-sfc", + "nvidia,tegra210-sfc"; + reg = <0x2902600 0x200>; + sound-name-prefix = "SFC4"; + status = "disabled"; + }; + + tegra_mvc1: mvc@290a000 { + compatible = "nvidia,tegra194-mvc", + "nvidia,tegra210-mvc"; + reg = <0x290a000 0x200>; + sound-name-prefix = "MVC1"; + status = "disabled"; + }; + + tegra_mvc2: mvc@290a200 { + compatible = "nvidia,tegra194-mvc", + "nvidia,tegra210-mvc"; + reg = <0x290a200 0x200>; + sound-name-prefix = "MVC2"; + status = "disabled"; + }; + + tegra_amx1: amx@2903000 { + compatible = "nvidia,tegra194-amx"; + reg = <0x2903000 0x100>; + sound-name-prefix = "AMX1"; + status = "disabled"; + }; + + tegra_amx2: amx@2903100 { + compatible = "nvidia,tegra194-amx"; + reg = <0x2903100 0x100>; + sound-name-prefix = "AMX2"; + status = "disabled"; + }; + + tegra_amx3: amx@2903200 { + compatible = "nvidia,tegra194-amx"; + reg = <0x2903200 0x100>; + sound-name-prefix = "AMX3"; + status = "disabled"; + }; + + tegra_amx4: amx@2903300 { + compatible = "nvidia,tegra194-amx"; + reg = <0x2903300 0x100>; + sound-name-prefix = "AMX4"; + status = "disabled"; + }; + + tegra_adx1: adx@2903800 { + compatible = "nvidia,tegra194-adx", + "nvidia,tegra210-adx"; + reg = <0x2903800 0x100>; + sound-name-prefix = "ADX1"; + status = "disabled"; + }; + + tegra_adx2: adx@2903900 { + compatible = "nvidia,tegra194-adx", + "nvidia,tegra210-adx"; + reg = <0x2903900 0x100>; + sound-name-prefix = "ADX2"; + status = "disabled"; + }; + + tegra_adx3: adx@2903a00 { + compatible = "nvidia,tegra194-adx", + "nvidia,tegra210-adx"; + reg = <0x2903a00 0x100>; + sound-name-prefix = "ADX3"; + status = "disabled"; + }; + + tegra_adx4: adx@2903b00 { + compatible = "nvidia,tegra194-adx", + "nvidia,tegra210-adx"; + reg = <0x2903b00 0x100>; + sound-name-prefix = "ADX4"; + status = "disabled"; + }; + + tegra_amixer: amixer@290bb00 { + compatible = "nvidia,tegra194-amixer", + "nvidia,tegra210-amixer"; + reg = <0x290bb00 0x800>; + sound-name-prefix = "MIXER"; + status = "disabled"; + }; }; };
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index 26b3f98a..b84c963 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -1641,6 +1641,83 @@ status = "disabled"; };
+ tegra_sfc1: sfc@702d2000 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2000 0x200>; + sound-name-prefix = "SFC1"; + status = "disabled"; + }; + + tegra_sfc2: sfc@702d2200 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2200 0x200>; + sound-name-prefix = "SFC2"; + status = "disabled"; + }; + + tegra_sfc3: sfc@702d2400 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2400 0x200>; + sound-name-prefix = "SFC3"; + status = "disabled"; + }; + + tegra_sfc4: sfc@702d2600 { + compatible = "nvidia,tegra210-sfc"; + reg = <0x702d2600 0x200>; + sound-name-prefix = "SFC4"; + status = "disabled"; + }; + + tegra_mvc1: mvc@702da000 { + compatible = "nvidia,tegra210-mvc"; + reg = <0x702da000 0x200>; + sound-name-prefix = "MVC1"; + status = "disabled"; + }; + + tegra_mvc2: mvc@702da200 { + compatible = "nvidia,tegra210-mvc"; + reg = <0x702da200 0x200>; + sound-name-prefix = "MVC2"; + status = "disabled"; + }; + + tegra_amx1: amx@702d3000 { + compatible = "nvidia,tegra210-amx"; + reg = <0x702d3000 0x100>; + sound-name-prefix = "AMX1"; + status = "disabled"; + }; + + tegra_amx2: amx@702d3100 { + compatible = "nvidia,tegra210-amx"; + reg = <0x702d3100 0x100>; + sound-name-prefix = "AMX2"; + status = "disabled"; + }; + + tegra_adx1: adx@702d3800 { + compatible = "nvidia,tegra210-adx"; + reg = <0x702d3800 0x100>; + sound-name-prefix = "ADX1"; + status = "disabled"; + }; + + tegra_adx2: adx@702d3900 { + compatible = "nvidia,tegra210-adx"; + reg = <0x702d3900 0x100>; + sound-name-prefix = "ADX2"; + status = "disabled"; + }; + + tegra_amixer: amixer@702dbb00 { + compatible = "nvidia,tegra210-amixer"; + reg = <0x702dbb00 0x800>; + sound-name-prefix = "MIXER"; + status = "disabled"; + }; + ports { #address-cells = <1>; #size-cells = <0>;
Extend APE audio support by adding more audio components such as SFC, MVC, AMX, ADX and Mixer. These components can be plugged into an audio path and required processing can be done. ASoC audio-graph based sound driver is used to facilitate this and thus extend sound bindings as well.
The components in the path may require different PCM parameters (such as sample rate, channels or sample size). Depending on the pre-defined audio paths, these can be statically configured with "convert-xxx" DT properties in endpoint subnode. The support for the rate and channel conversion is already available in generic audio-graph driver. Sample size conversion support can be added based on the need in future.
The support is extended for following platforms: * Jertson TX1 * Jetson Nano * Jetson TX2 * Jetson AGX Xavier * Jetson Xavier NX
Signed-off-by: Sameer Pujar spujar@nvidia.com --- arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts | 1554 ++++++++++++++++++-- arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts | 1493 +++++++++++++++++-- .../arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi | 1520 +++++++++++++++++-- arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 876 +++++++++++ arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts | 876 +++++++++++ 5 files changed, 5900 insertions(+), 419 deletions(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts index 74c1a5d..52fa258 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts @@ -275,178 +275,1097 @@ remote-endpoint = <&dspk2_cif_ep>; }; }; + + xbar_sfc1_in_port: port@20 { + reg = <0x20>; + + xbar_sfc1_in_ep: endpoint { + remote-endpoint = <&sfc1_cif_in_ep>; + }; + }; + + port@21 { + reg = <0x21>; + + xbar_sfc1_out_ep: endpoint { + remote-endpoint = <&sfc1_cif_out_ep>; + }; + }; + + xbar_sfc2_in_port: port@22 { + reg = <0x22>; + + xbar_sfc2_in_ep: endpoint { + remote-endpoint = <&sfc2_cif_in_ep>; + }; + }; + + port@23 { + reg = <0x23>; + + xbar_sfc2_out_ep: endpoint { + remote-endpoint = <&sfc2_cif_out_ep>; + }; + }; + + xbar_sfc3_in_port: port@24 { + reg = <0x24>; + + xbar_sfc3_in_ep: endpoint { + remote-endpoint = <&sfc3_cif_in_ep>; + }; + }; + + port@25 { + reg = <0x25>; + + xbar_sfc3_out_ep: endpoint { + remote-endpoint = <&sfc3_cif_out_ep>; + }; + }; + + xbar_sfc4_in_port: port@26 { + reg = <0x26>; + + xbar_sfc4_in_ep: endpoint { + remote-endpoint = <&sfc4_cif_in_ep>; + }; + }; + + port@27 { + reg = <0x27>; + + xbar_sfc4_out_ep: endpoint { + remote-endpoint = <&sfc4_cif_out_ep>; + }; + }; + + xbar_mvc1_in_port: port@28 { + reg = <0x28>; + + xbar_mvc1_in_ep: endpoint { + remote-endpoint = <&mvc1_cif_in_ep>; + }; + }; + + port@29 { + reg = <0x29>; + + xbar_mvc1_out_ep: endpoint { + remote-endpoint = <&mvc1_cif_out_ep>; + }; + }; + + xbar_mvc2_in_port: port@2a { + reg = <0x2a>; + + xbar_mvc2_in_ep: endpoint { + remote-endpoint = <&mvc2_cif_in_ep>; + }; + }; + + port@2b { + reg = <0x2b>; + + xbar_mvc2_out_ep: endpoint { + remote-endpoint = <&mvc2_cif_out_ep>; + }; + }; + + xbar_amx1_in1_port: port@2c { + reg = <0x2c>; + + xbar_amx1_in1_ep: endpoint { + remote-endpoint = <&amx1_in1_ep>; + }; + }; + + xbar_amx1_in2_port: port@2d { + reg = <0x2d>; + + xbar_amx1_in2_ep: endpoint { + remote-endpoint = <&amx1_in2_ep>; + }; + }; + + xbar_amx1_in3_port: port@2e { + reg = <0x2e>; + + xbar_amx1_in3_ep: endpoint { + remote-endpoint = <&amx1_in3_ep>; + }; + }; + + xbar_amx1_in4_port: port@2f { + reg = <0x2f>; + + xbar_amx1_in4_ep: endpoint { + remote-endpoint = <&amx1_in4_ep>; + }; + }; + + port@30 { + reg = <0x30>; + + xbar_amx1_out_ep: endpoint { + remote-endpoint = <&amx1_out_ep>; + }; + }; + + xbar_amx2_in1_port: port@31 { + reg = <0x31>; + + xbar_amx2_in1_ep: endpoint { + remote-endpoint = <&amx2_in1_ep>; + }; + }; + + xbar_amx2_in2_port: port@32 { + reg = <0x32>; + + xbar_amx2_in2_ep: endpoint { + remote-endpoint = <&amx2_in2_ep>; + }; + }; + + xbar_amx2_in3_port: port@33 { + reg = <0x33>; + + xbar_amx2_in3_ep: endpoint { + remote-endpoint = <&amx2_in3_ep>; + }; + }; + + xbar_amx2_in4_port: port@34 { + reg = <0x34>; + + xbar_amx2_in4_ep: endpoint { + remote-endpoint = <&amx2_in4_ep>; + }; + }; + + port@35 { + reg = <0x35>; + + xbar_amx2_out_ep: endpoint { + remote-endpoint = <&amx2_out_ep>; + }; + }; + + xbar_amx3_in1_port: port@36 { + reg = <0x36>; + + xbar_amx3_in1_ep: endpoint { + remote-endpoint = <&amx3_in1_ep>; + }; + }; + + xbar_amx3_in2_port: port@37 { + reg = <0x37>; + + xbar_amx3_in2_ep: endpoint { + remote-endpoint = <&amx3_in2_ep>; + }; + }; + + xbar_amx3_in3_port: port@38 { + reg = <0x38>; + + xbar_amx3_in3_ep: endpoint { + remote-endpoint = <&amx3_in3_ep>; + }; + }; + + xbar_amx3_in4_port: port@39 { + reg = <0x39>; + + xbar_amx3_in4_ep: endpoint { + remote-endpoint = <&amx3_in4_ep>; + }; + }; + + port@3a { + reg = <0x3a>; + + xbar_amx3_out_ep: endpoint { + remote-endpoint = <&amx3_out_ep>; + }; + }; + + xbar_amx4_in1_port: port@3b { + reg = <0x3b>; + + xbar_amx4_in1_ep: endpoint { + remote-endpoint = <&amx4_in1_ep>; + }; + }; + + xbar_amx4_in2_port: port@3c { + reg = <0x3c>; + + xbar_amx4_in2_ep: endpoint { + remote-endpoint = <&amx4_in2_ep>; + }; + }; + + xbar_amx4_in3_port: port@3d { + reg = <0x3d>; + + xbar_amx4_in3_ep: endpoint { + remote-endpoint = <&amx4_in3_ep>; + }; + }; + + xbar_amx4_in4_port: port@3e { + reg = <0x3e>; + + xbar_amx4_in4_ep: endpoint { + remote-endpoint = <&amx4_in4_ep>; + }; + }; + + port@3f { + reg = <0x3f>; + + xbar_amx4_out_ep: endpoint { + remote-endpoint = <&amx4_out_ep>; + }; + }; + + xbar_adx1_in_port: port@40 { + reg = <0x40>; + + xbar_adx1_in_ep: endpoint { + remote-endpoint = <&adx1_in_ep>; + }; + }; + + port@41 { + reg = <0x41>; + + xbar_adx1_out1_ep: endpoint { + remote-endpoint = <&adx1_out1_ep>; + }; + }; + + port@42 { + reg = <0x42>; + + xbar_adx1_out2_ep: endpoint { + remote-endpoint = <&adx1_out2_ep>; + }; + }; + + port@43 { + reg = <0x43>; + + xbar_adx1_out3_ep: endpoint { + remote-endpoint = <&adx1_out3_ep>; + }; + }; + + port@44 { + reg = <0x44>; + + xbar_adx1_out4_ep: endpoint { + remote-endpoint = <&adx1_out4_ep>; + }; + }; + + xbar_adx2_in_port: port@45 { + reg = <0x45>; + + xbar_adx2_in_ep: endpoint { + remote-endpoint = <&adx2_in_ep>; + }; + }; + + port@46 { + reg = <0x46>; + + xbar_adx2_out1_ep: endpoint { + remote-endpoint = <&adx2_out1_ep>; + }; + }; + + port@47 { + reg = <0x47>; + + xbar_adx2_out2_ep: endpoint { + remote-endpoint = <&adx2_out2_ep>; + }; + }; + + port@48 { + reg = <0x48>; + + xbar_adx2_out3_ep: endpoint { + remote-endpoint = <&adx2_out3_ep>; + }; + }; + + port@49 { + reg = <0x49>; + + xbar_adx2_out4_ep: endpoint { + remote-endpoint = <&adx2_out4_ep>; + }; + }; + + xbar_adx3_in_port: port@4a { + reg = <0x4a>; + + xbar_adx3_in_ep: endpoint { + remote-endpoint = <&adx3_in_ep>; + }; + }; + + port@4b { + reg = <0x4b>; + + xbar_adx3_out1_ep: endpoint { + remote-endpoint = <&adx3_out1_ep>; + }; + }; + + port@4c { + reg = <0x4c>; + + xbar_adx3_out2_ep: endpoint { + remote-endpoint = <&adx3_out2_ep>; + }; + }; + + port@4d { + reg = <0x4d>; + + xbar_adx3_out3_ep: endpoint { + remote-endpoint = <&adx3_out3_ep>; + }; + }; + + port@4e { + reg = <0x4e>; + + xbar_adx3_out4_ep: endpoint { + remote-endpoint = <&adx3_out4_ep>; + }; + }; + + xbar_adx4_in_port: port@4f { + reg = <0x4f>; + + xbar_adx4_in_ep: endpoint { + remote-endpoint = <&adx4_in_ep>; + }; + }; + + port@50 { + reg = <0x50>; + + xbar_adx4_out1_ep: endpoint { + remote-endpoint = <&adx4_out1_ep>; + }; + }; + + port@51 { + reg = <0x51>; + + xbar_adx4_out2_ep: endpoint { + remote-endpoint = <&adx4_out2_ep>; + }; + }; + + port@52 { + reg = <0x52>; + + xbar_adx4_out3_ep: endpoint { + remote-endpoint = <&adx4_out3_ep>; + }; + }; + + port@53 { + reg = <0x53>; + + xbar_adx4_out4_ep: endpoint { + remote-endpoint = <&adx4_out4_ep>; + }; + }; + + xbar_mixer_in1_port: port@54 { + reg = <0x54>; + + xbar_mixer_in1_ep: endpoint { + remote-endpoint = <&mixer_in1_ep>; + }; + }; + + xbar_mixer_in2_port: port@55 { + reg = <0x55>; + + xbar_mixer_in2_ep: endpoint { + remote-endpoint = <&mixer_in2_ep>; + }; + }; + + xbar_mixer_in3_port: port@56 { + reg = <0x56>; + + xbar_mixer_in3_ep: endpoint { + remote-endpoint = <&mixer_in3_ep>; + }; + }; + + xbar_mixer_in4_port: port@57 { + reg = <0x57>; + + xbar_mixer_in4_ep: endpoint { + remote-endpoint = <&mixer_in4_ep>; + }; + }; + + xbar_mixer_in5_port: port@58 { + reg = <0x58>; + + xbar_mixer_in5_ep: endpoint { + remote-endpoint = <&mixer_in5_ep>; + }; + }; + + xbar_mixer_in6_port: port@59 { + reg = <0x59>; + + xbar_mixer_in6_ep: endpoint { + remote-endpoint = <&mixer_in6_ep>; + }; + }; + + xbar_mixer_in7_port: port@5a { + reg = <0x5a>; + + xbar_mixer_in7_ep: endpoint { + remote-endpoint = <&mixer_in7_ep>; + }; + }; + + xbar_mixer_in8_port: port@5b { + reg = <0x5b>; + + xbar_mixer_in8_ep: endpoint { + remote-endpoint = <&mixer_in8_ep>; + }; + }; + + xbar_mixer_in9_port: port@5c { + reg = <0x5c>; + + xbar_mixer_in9_ep: endpoint { + remote-endpoint = <&mixer_in9_ep>; + }; + }; + + xbar_mixer_in10_port: port@5d { + reg = <0x5d>; + + xbar_mixer_in10_ep: endpoint { + remote-endpoint = <&mixer_in10_ep>; + }; + }; + + port@5e { + reg = <0x5e>; + + xbar_mixer_out1_ep: endpoint { + remote-endpoint = <&mixer_out1_ep>; + }; + }; + + port@5f { + reg = <0x5f>; + + xbar_mixer_out2_ep: endpoint { + remote-endpoint = <&mixer_out2_ep>; + }; + }; + + port@60 { + reg = <0x60>; + + xbar_mixer_out3_ep: endpoint { + remote-endpoint = <&mixer_out3_ep>; + }; + }; + + port@61 { + reg = <0x61>; + + xbar_mixer_out4_ep: endpoint { + remote-endpoint = <&mixer_out4_ep>; + }; + }; + + port@62 { + reg = <0x62>; + + xbar_mixer_out5_ep: endpoint { + remote-endpoint = <&mixer_out5_ep>; + }; + }; + }; + + admaif@290f000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + admaif0_port: port@0 { + reg = <0x0>; + + admaif0_ep: endpoint { + remote-endpoint = <&xbar_admaif0_ep>; + }; + }; + + admaif1_port: port@1 { + reg = <0x1>; + + admaif1_ep: endpoint { + remote-endpoint = <&xbar_admaif1_ep>; + }; + }; + + admaif2_port: port@2 { + reg = <0x2>; + + admaif2_ep: endpoint { + remote-endpoint = <&xbar_admaif2_ep>; + }; + }; + + admaif3_port: port@3 { + reg = <0x3>; + + admaif3_ep: endpoint { + remote-endpoint = <&xbar_admaif3_ep>; + }; + }; + + admaif4_port: port@4 { + reg = <0x4>; + + admaif4_ep: endpoint { + remote-endpoint = <&xbar_admaif4_ep>; + }; + }; + + admaif5_port: port@5 { + reg = <0x5>; + + admaif5_ep: endpoint { + remote-endpoint = <&xbar_admaif5_ep>; + }; + }; + + admaif6_port: port@6 { + reg = <0x6>; + + admaif6_ep: endpoint { + remote-endpoint = <&xbar_admaif6_ep>; + }; + }; + + admaif7_port: port@7 { + reg = <0x7>; + + admaif7_ep: endpoint { + remote-endpoint = <&xbar_admaif7_ep>; + }; + }; + + admaif8_port: port@8 { + reg = <0x8>; + + admaif8_ep: endpoint { + remote-endpoint = <&xbar_admaif8_ep>; + }; + }; + + admaif9_port: port@9 { + reg = <0x9>; + + admaif9_ep: endpoint { + remote-endpoint = <&xbar_admaif9_ep>; + }; + }; + + admaif10_port: port@a { + reg = <0xa>; + + admaif10_ep: endpoint { + remote-endpoint = <&xbar_admaif10_ep>; + }; + }; + + admaif11_port: port@b { + reg = <0xb>; + + admaif11_ep: endpoint { + remote-endpoint = <&xbar_admaif11_ep>; + }; + }; + + admaif12_port: port@c { + reg = <0xc>; + + admaif12_ep: endpoint { + remote-endpoint = <&xbar_admaif12_ep>; + }; + }; + + admaif13_port: port@d { + reg = <0xd>; + + admaif13_ep: endpoint { + remote-endpoint = <&xbar_admaif13_ep>; + }; + }; + + admaif14_port: port@e { + reg = <0xe>; + + admaif14_ep: endpoint { + remote-endpoint = <&xbar_admaif14_ep>; + }; + }; + + admaif15_port: port@f { + reg = <0xf>; + + admaif15_ep: endpoint { + remote-endpoint = <&xbar_admaif15_ep>; + }; + }; + + admaif16_port: port@10 { + reg = <0x10>; + + admaif16_ep: endpoint { + remote-endpoint = <&xbar_admaif16_ep>; + }; + }; + + admaif17_port: port@11 { + reg = <0x11>; + + admaif17_ep: endpoint { + remote-endpoint = <&xbar_admaif17_ep>; + }; + }; + + admaif18_port: port@12 { + reg = <0x12>; + + admaif18_ep: endpoint { + remote-endpoint = <&xbar_admaif18_ep>; + }; + }; + + admaif19_port: port@13 { + reg = <0x13>; + + admaif19_ep: endpoint { + remote-endpoint = <&xbar_admaif19_ep>; + }; + }; + }; + }; + + i2s@2901000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s1_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s1_ep>; + }; + }; + + i2s1_port: port@1 { + reg = <1>; + + i2s1_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ + }; + }; + }; + }; + + i2s@2901100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s2_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s2_ep>; + }; + }; + + i2s2_port: port@1 { + reg = <1>; + + i2s2_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ + }; + }; + }; + }; + + i2s@2901200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s3_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s3_ep>; + }; + }; + + i2s3_port: port@1 { + reg = <1>; + + i2s3_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ + }; + }; + }; };
- admaif@290f000 { + i2s@2901300 { status = "okay";
ports { #address-cells = <1>; #size-cells = <0>;
- admaif0_port: port@0 { - reg = <0x0>; + port@0 { + reg = <0>;
- admaif0_ep: endpoint { - remote-endpoint = <&xbar_admaif0_ep>; + i2s4_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s4_ep>; }; };
- admaif1_port: port@1 { - reg = <0x1>; + i2s4_port: port@1 { + reg = <1>;
- admaif1_ep: endpoint { - remote-endpoint = <&xbar_admaif1_ep>; + i2s4_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ }; }; + }; + };
- admaif2_port: port@2 { - reg = <0x2>; + i2s@2901400 { + status = "okay";
- admaif2_ep: endpoint { - remote-endpoint = <&xbar_admaif2_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s5_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s5_ep>; }; };
- admaif3_port: port@3 { - reg = <0x3>; + i2s5_port: port@1 { + reg = <1>;
- admaif3_ep: endpoint { - remote-endpoint = <&xbar_admaif3_ep>; + i2s5_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ }; }; + }; + };
- admaif4_port: port@4 { - reg = <0x4>; + i2s@2901500 { + status = "okay";
- admaif4_ep: endpoint { - remote-endpoint = <&xbar_admaif4_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s6_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s6_ep>; }; };
- admaif5_port: port@5 { - reg = <0x5>; + i2s6_port: port@1 { + reg = <1>;
- admaif5_ep: endpoint { - remote-endpoint = <&xbar_admaif5_ep>; + i2s6_dap_ep: endpoint { + dai-format = "i2s"; + /* Placeholder for external Codec */ }; }; + }; + };
- admaif6_port: port@6 { - reg = <0x6>; + dmic@2904000 { + status = "okay";
- admaif6_ep: endpoint { - remote-endpoint = <&xbar_admaif6_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic1_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic1_ep>; }; };
- admaif7_port: port@7 { - reg = <0x7>; + dmic1_port: port@1 { + reg = <1>;
- admaif7_ep: endpoint { - remote-endpoint = <&xbar_admaif7_ep>; + dmic1_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif8_port: port@8 { - reg = <0x8>; + dmic@2904100 { + status = "okay";
- admaif8_ep: endpoint { - remote-endpoint = <&xbar_admaif8_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic2_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic2_ep>; }; };
- admaif9_port: port@9 { - reg = <0x9>; + dmic2_port: port@1 { + reg = <1>;
- admaif9_ep: endpoint { - remote-endpoint = <&xbar_admaif9_ep>; + dmic2_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif10_port: port@a { - reg = <0xa>; + dmic@2904200 { + status = "okay";
- admaif10_ep: endpoint { - remote-endpoint = <&xbar_admaif10_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic3_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic3_ep>; }; };
- admaif11_port: port@b { - reg = <0xb>; + dmic3_port: port@1 { + reg = <1>;
- admaif11_ep: endpoint { - remote-endpoint = <&xbar_admaif11_ep>; + dmic3_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif12_port: port@c { - reg = <0xc>; + dspk@2905000 { + status = "okay";
- admaif12_ep: endpoint { - remote-endpoint = <&xbar_admaif12_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk1_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk1_ep>; }; };
- admaif13_port: port@d { - reg = <0xd>; + dspk1_port: port@1 { + reg = <1>;
- admaif13_ep: endpoint { - remote-endpoint = <&xbar_admaif13_ep>; + dspk1_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif14_port: port@e { - reg = <0xe>; + dspk@2905100 { + status = "okay";
- admaif14_ep: endpoint { - remote-endpoint = <&xbar_admaif14_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk2_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk2_ep>; }; };
- admaif15_port: port@f { - reg = <0xf>; + dspk2_port: port@1 { + reg = <1>;
- admaif15_ep: endpoint { - remote-endpoint = <&xbar_admaif15_ep>; + dspk2_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif16_port: port@10 { - reg = <0x10>; + sfc@2902000 { + status = "okay";
- admaif16_ep: endpoint { - remote-endpoint = <&xbar_admaif16_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc1_in_ep>; + convert-rate = <44100>; }; };
- admaif17_port: port@11 { - reg = <0x11>; + sfc1_out_port: port@1 { + reg = <1>;
- admaif17_ep: endpoint { - remote-endpoint = <&xbar_admaif17_ep>; + sfc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc1_out_ep>; + convert-rate = <48000>; + }; + }; + }; + }; + + sfc@2902200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc2_in_ep>; + }; + }; + + sfc2_out_port: port@1 { + reg = <1>; + + sfc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc2_out_ep>; + }; + }; + }; + }; + + sfc@2902400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc3_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc3_in_ep>; + }; + }; + + sfc3_out_port: port@1 { + reg = <1>; + + sfc3_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc3_out_ep>; }; }; + }; + };
- admaif18_port: port@12 { - reg = <0x12>; + sfc@2902600 { + status = "okay";
- admaif18_ep: endpoint { - remote-endpoint = <&xbar_admaif18_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc4_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc4_in_ep>; }; };
- admaif19_port: port@13 { - reg = <0x13>; + sfc4_out_port: port@1 { + reg = <1>;
- admaif19_ep: endpoint { - remote-endpoint = <&xbar_admaif19_ep>; + sfc4_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc4_out_ep>; }; }; }; };
- i2s@2901000 { + mvc@290a000 { status = "okay";
ports { @@ -456,23 +1375,22 @@ port@0 { reg = <0>;
- i2s1_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s1_ep>; + mvc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc1_in_ep>; }; };
- i2s1_port: port@1 { + mvc1_out_port: port@1 { reg = <1>;
- i2s1_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + mvc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc1_out_ep>; }; }; }; };
- i2s@2901100 { + mvc@290a200 { status = "okay";
ports { @@ -482,23 +1400,22 @@ port@0 { reg = <0>;
- i2s2_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s2_ep>; + mvc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc2_in_ep>; }; };
- i2s2_port: port@1 { + mvc2_out_port: port@1 { reg = <1>;
- i2s2_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + mvc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc2_out_ep>; }; }; }; };
- i2s@2901200 { + amx@2903000 { status = "okay";
ports { @@ -508,23 +1425,46 @@ port@0 { reg = <0>;
- i2s3_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s3_ep>; + amx1_in1_ep: endpoint { + remote-endpoint = <&xbar_amx1_in1_ep>; }; };
- i2s3_port: port@1 { + port@1 { reg = <1>;
- i2s3_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + amx1_in2_ep: endpoint { + remote-endpoint = <&xbar_amx1_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx1_in3_ep: endpoint { + remote-endpoint = <&xbar_amx1_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx1_in4_ep: endpoint { + remote-endpoint = <&xbar_amx1_in4_ep>; + }; + }; + + amx1_out_port: port@4 { + reg = <4>; + + amx1_out_ep: endpoint { + remote-endpoint = <&xbar_amx1_out_ep>; }; }; }; };
- i2s@2901300 { + amx@2903100 { status = "okay";
ports { @@ -534,23 +1474,46 @@ port@0 { reg = <0>;
- i2s4_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s4_ep>; + amx2_in1_ep: endpoint { + remote-endpoint = <&xbar_amx2_in1_ep>; }; };
- i2s4_port: port@1 { + port@1 { reg = <1>;
- i2s4_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + amx2_in2_ep: endpoint { + remote-endpoint = <&xbar_amx2_in2_ep>; + }; + }; + + amx2_in3_port: port@2 { + reg = <2>; + + amx2_in3_ep: endpoint { + remote-endpoint = <&xbar_amx2_in3_ep>; + }; + }; + + amx2_in4_port: port@3 { + reg = <3>; + + amx2_in4_ep: endpoint { + remote-endpoint = <&xbar_amx2_in4_ep>; + }; + }; + + amx2_out_port: port@4 { + reg = <4>; + + amx2_out_ep: endpoint { + remote-endpoint = <&xbar_amx2_out_ep>; }; }; }; };
- i2s@2901400 { + amx@2903200 { status = "okay";
ports { @@ -560,23 +1523,46 @@ port@0 { reg = <0>;
- i2s5_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s5_ep>; + amx3_in1_ep: endpoint { + remote-endpoint = <&xbar_amx3_in1_ep>; }; };
- i2s5_port: port@1 { + port@1 { reg = <1>;
- i2s5_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + amx3_in2_ep: endpoint { + remote-endpoint = <&xbar_amx3_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx3_in3_ep: endpoint { + remote-endpoint = <&xbar_amx3_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx3_in4_ep: endpoint { + remote-endpoint = <&xbar_amx3_in4_ep>; + }; + }; + + amx3_out_port: port@4 { + reg = <4>; + + amx3_out_ep: endpoint { + remote-endpoint = <&xbar_amx3_out_ep>; }; }; }; };
- i2s@2901500 { + amx@2903300 { status = "okay";
ports { @@ -586,23 +1572,46 @@ port@0 { reg = <0>;
- i2s6_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s6_ep>; + amx4_in1_ep: endpoint { + remote-endpoint = <&xbar_amx4_in1_ep>; }; };
- i2s6_port: port@1 { + port@1 { reg = <1>;
- i2s6_dap_ep: endpoint { - dai-format = "i2s"; - /* Placeholder for external Codec */ + amx4_in2_ep: endpoint { + remote-endpoint = <&xbar_amx4_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx4_in3_ep: endpoint { + remote-endpoint = <&xbar_amx4_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx4_in4_ep: endpoint { + remote-endpoint = <&xbar_amx4_in4_ep>; + }; + }; + + amx4_out_port: port@4 { + reg = <4>; + + amx4_out_ep: endpoint { + remote-endpoint = <&xbar_amx4_out_ep>; }; }; }; };
- dmic@2904000 { + adx@2903800 { status = "okay";
ports { @@ -612,22 +1621,46 @@ port@0 { reg = <0>;
- dmic1_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic1_ep>; + adx1_in_ep: endpoint { + remote-endpoint = <&xbar_adx1_in_ep>; }; };
- dmic1_port: port@1 { + adx1_out1_port: port@1 { reg = <1>;
- dmic1_dap_ep: endpoint { - /* Place holder for external Codec */ + adx1_out1_ep: endpoint { + remote-endpoint = <&xbar_adx1_out1_ep>; + }; + }; + + adx1_out2_port: port@2 { + reg = <2>; + + adx1_out2_ep: endpoint { + remote-endpoint = <&xbar_adx1_out2_ep>; + }; + }; + + adx1_out3_port: port@3 { + reg = <3>; + + adx1_out3_ep: endpoint { + remote-endpoint = <&xbar_adx1_out3_ep>; + }; + }; + + adx1_out4_port: port@4 { + reg = <4>; + + adx1_out4_ep: endpoint { + remote-endpoint = <&xbar_adx1_out4_ep>; }; }; }; };
- dmic@2904100 { + adx@2903900 { status = "okay";
ports { @@ -637,22 +1670,46 @@ port@0 { reg = <0>;
- dmic2_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic2_ep>; + adx2_in_ep: endpoint { + remote-endpoint = <&xbar_adx2_in_ep>; }; };
- dmic2_port: port@1 { + adx2_out1_port: port@1 { reg = <1>;
- dmic2_dap_ep: endpoint { - /* Place holder for external Codec */ + adx2_out1_ep: endpoint { + remote-endpoint = <&xbar_adx2_out1_ep>; + }; + }; + + adx2_out2_port: port@2 { + reg = <2>; + + adx2_out2_ep: endpoint { + remote-endpoint = <&xbar_adx2_out2_ep>; + }; + }; + + adx2_out3_port: port@3 { + reg = <3>; + + adx2_out3_ep: endpoint { + remote-endpoint = <&xbar_adx2_out3_ep>; + }; + }; + + adx2_out4_port: port@4 { + reg = <4>; + + adx2_out4_ep: endpoint { + remote-endpoint = <&xbar_adx2_out4_ep>; }; }; }; };
- dmic@2904200 { + adx@2903a00 { status = "okay";
ports { @@ -662,22 +1719,46 @@ port@0 { reg = <0>;
- dmic3_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic3_ep>; + adx3_in_ep: endpoint { + remote-endpoint = <&xbar_adx3_in_ep>; }; };
- dmic3_port: port@1 { + adx3_out1_port: port@1 { reg = <1>;
- dmic3_dap_ep: endpoint { - /* Place holder for external Codec */ + adx3_out1_ep: endpoint { + remote-endpoint = <&xbar_adx3_out1_ep>; + }; + }; + + adx3_out2_port: port@2 { + reg = <2>; + + adx3_out2_ep: endpoint { + remote-endpoint = <&xbar_adx3_out2_ep>; + }; + }; + + adx3_out3_port: port@3 { + reg = <3>; + + adx3_out3_ep: endpoint { + remote-endpoint = <&xbar_adx3_out3_ep>; + }; + }; + + adx3_out4_port: port@4 { + reg = <4>; + + adx3_out4_ep: endpoint { + remote-endpoint = <&xbar_adx3_out4_ep>; }; }; }; };
- dspk@2905000 { + adx@2903b00 { status = "okay";
ports { @@ -687,22 +1768,46 @@ port@0 { reg = <0>;
- dspk1_cif_ep: endpoint { - remote-endpoint = <&xbar_dspk1_ep>; + adx4_in_ep: endpoint { + remote-endpoint = <&xbar_adx4_in_ep>; }; };
- dspk1_port: port@1 { + adx4_out1_port: port@1 { reg = <1>;
- dspk1_dap_ep: endpoint { - /* Place holder for external Codec */ + adx4_out1_ep: endpoint { + remote-endpoint = <&xbar_adx4_out1_ep>; + }; + }; + + adx4_out2_port: port@2 { + reg = <2>; + + adx4_out2_ep: endpoint { + remote-endpoint = <&xbar_adx4_out2_ep>; + }; + }; + + adx4_out3_port: port@3 { + reg = <3>; + + adx4_out3_ep: endpoint { + remote-endpoint = <&xbar_adx4_out3_ep>; + }; + }; + + adx4_out4_port: port@4 { + reg = <4>; + + adx4_out4_ep: endpoint { + remote-endpoint = <&xbar_adx4_out4_ep>; }; }; }; };
- dspk@2905100 { + amixer@290bb00 { status = "okay";
ports { @@ -710,18 +1815,122 @@ #size-cells = <0>;
port@0 { - reg = <0>; + reg = <0x0>;
- dspk2_cif_ep: endpoint { - remote-endpoint = <&xbar_dspk2_ep>; + mixer_in1_ep: endpoint { + remote-endpoint = <&xbar_mixer_in1_ep>; }; };
- dspk2_port: port@1 { - reg = <1>; + port@1 { + reg = <0x1>;
- dspk2_dap_ep: endpoint { - /* Place holder for external Codec */ + mixer_in2_ep: endpoint { + remote-endpoint = <&xbar_mixer_in2_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + mixer_in3_ep: endpoint { + remote-endpoint = <&xbar_mixer_in3_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + mixer_in4_ep: endpoint { + remote-endpoint = <&xbar_mixer_in4_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + mixer_in5_ep: endpoint { + remote-endpoint = <&xbar_mixer_in5_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + mixer_in6_ep: endpoint { + remote-endpoint = <&xbar_mixer_in6_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + mixer_in7_ep: endpoint { + remote-endpoint = <&xbar_mixer_in7_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + mixer_in8_ep: endpoint { + remote-endpoint = <&xbar_mixer_in8_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + mixer_in9_ep: endpoint { + remote-endpoint = <&xbar_mixer_in9_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + mixer_in10_ep: endpoint { + remote-endpoint = <&xbar_mixer_in10_ep>; + }; + }; + + mixer_out1_port: port@a { + reg = <0xa>; + + mixer_out1_ep: endpoint { + remote-endpoint = <&xbar_mixer_out1_ep>; + }; + }; + + mixer_out2_port: port@b { + reg = <0xb>; + + mixer_out2_ep: endpoint { + remote-endpoint = <&xbar_mixer_out2_ep>; + }; + }; + + mixer_out3_port: port@c { + reg = <0xc>; + + mixer_out3_ep: endpoint { + remote-endpoint = <&xbar_mixer_out3_ep>; + }; + }; + + mixer_out4_port: port@d { + reg = <0xd>; + + mixer_out4_ep: endpoint { + remote-endpoint = <&xbar_mixer_out4_ep>; + }; + }; + + mixer_out5_port: port@e { + reg = <0xe>; + + mixer_out5_ep: endpoint { + remote-endpoint = <&xbar_mixer_out5_ep>; }; }; }; @@ -1104,6 +2313,41 @@ <&xbar_i2s4_port>, <&xbar_i2s5_port>, <&xbar_i2s6_port>, <&xbar_dmic1_port>, <&xbar_dmic2_port>, <&xbar_dmic3_port>, <&xbar_dspk1_port>, <&xbar_dspk2_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>, + <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>, + <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>, + <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_adx3_in_port>, <&xbar_adx4_in_port>, + <&xbar_mixer_in1_port>, <&xbar_mixer_in2_port>, + <&xbar_mixer_in3_port>, <&xbar_mixer_in4_port>, + <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>, + <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>, + <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&amx3_out_port>, <&amx4_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&adx3_out1_port>, <&adx3_out2_port>, + <&adx3_out3_port>, <&adx3_out4_port>, + <&adx4_out1_port>, <&adx4_out2_port>, + <&adx4_out3_port>, <&adx4_out4_port>, + <&mixer_out1_port>, <&mixer_out2_port>, + <&mixer_out3_port>, <&mixer_out4_port>, + <&mixer_out5_port>, /* I/O */ <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>, <&i2s5_port>, <&i2s6_port>, <&dmic1_port>, <&dmic2_port>, diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts index 96bd01c..fab34d6 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dts @@ -228,178 +228,1238 @@ remote-endpoint = <&dmic3_cif_ep>; }; }; + + xbar_sfc1_in_port: port@20 { + reg = <0x20>; + + xbar_sfc1_in_ep: endpoint { + remote-endpoint = <&sfc1_cif_in_ep>; + }; + }; + + port@21 { + reg = <0x21>; + + xbar_sfc1_out_ep: endpoint { + remote-endpoint = <&sfc1_cif_out_ep>; + }; + }; + + xbar_sfc2_in_port: port@22 { + reg = <0x22>; + + xbar_sfc2_in_ep: endpoint { + remote-endpoint = <&sfc2_cif_in_ep>; + }; + }; + + port@23 { + reg = <0x23>; + + xbar_sfc2_out_ep: endpoint { + remote-endpoint = <&sfc2_cif_out_ep>; + }; + }; + + xbar_sfc3_in_port: port@24 { + reg = <0x24>; + + xbar_sfc3_in_ep: endpoint { + remote-endpoint = <&sfc3_cif_in_ep>; + }; + }; + + port@25 { + reg = <0x25>; + + xbar_sfc3_out_ep: endpoint { + remote-endpoint = <&sfc3_cif_out_ep>; + }; + }; + + xbar_sfc4_in_port: port@26 { + reg = <0x26>; + + xbar_sfc4_in_ep: endpoint { + remote-endpoint = <&sfc4_cif_in_ep>; + }; + }; + + port@27 { + reg = <0x27>; + + xbar_sfc4_out_ep: endpoint { + remote-endpoint = <&sfc4_cif_out_ep>; + }; + }; + + xbar_mvc1_in_port: port@28 { + reg = <0x28>; + + xbar_mvc1_in_ep: endpoint { + remote-endpoint = <&mvc1_cif_in_ep>; + }; + }; + + port@29 { + reg = <0x29>; + + xbar_mvc1_out_ep: endpoint { + remote-endpoint = <&mvc1_cif_out_ep>; + }; + }; + + xbar_mvc2_in_port: port@2a { + reg = <0x2a>; + + xbar_mvc2_in_ep: endpoint { + remote-endpoint = <&mvc2_cif_in_ep>; + }; + }; + + port@2b { + reg = <0x2b>; + + xbar_mvc2_out_ep: endpoint { + remote-endpoint = <&mvc2_cif_out_ep>; + }; + }; + + xbar_amx1_in1_port: port@2c { + reg = <0x2c>; + + xbar_amx1_in1_ep: endpoint { + remote-endpoint = <&amx1_in1_ep>; + }; + }; + + xbar_amx1_in2_port: port@2d { + reg = <0x2d>; + + xbar_amx1_in2_ep: endpoint { + remote-endpoint = <&amx1_in2_ep>; + }; + }; + + xbar_amx1_in3_port: port@2e { + reg = <0x2e>; + + xbar_amx1_in3_ep: endpoint { + remote-endpoint = <&amx1_in3_ep>; + }; + }; + + xbar_amx1_in4_port: port@2f { + reg = <0x2f>; + + xbar_amx1_in4_ep: endpoint { + remote-endpoint = <&amx1_in4_ep>; + }; + }; + + port@30 { + reg = <0x30>; + + xbar_amx1_out_ep: endpoint { + remote-endpoint = <&amx1_out_ep>; + }; + }; + + xbar_amx2_in1_port: port@31 { + reg = <0x31>; + + xbar_amx2_in1_ep: endpoint { + remote-endpoint = <&amx2_in1_ep>; + }; + }; + + xbar_amx2_in2_port: port@32 { + reg = <0x32>; + + xbar_amx2_in2_ep: endpoint { + remote-endpoint = <&amx2_in2_ep>; + }; + }; + + xbar_amx2_in3_port: port@33 { + reg = <0x33>; + + xbar_amx2_in3_ep: endpoint { + remote-endpoint = <&amx2_in3_ep>; + }; + }; + + xbar_amx2_in4_port: port@34 { + reg = <0x34>; + + xbar_amx2_in4_ep: endpoint { + remote-endpoint = <&amx2_in4_ep>; + }; + }; + + port@35 { + reg = <0x35>; + + xbar_amx2_out_ep: endpoint { + remote-endpoint = <&amx2_out_ep>; + }; + }; + + xbar_amx3_in1_port: port@36 { + reg = <0x36>; + + xbar_amx3_in1_ep: endpoint { + remote-endpoint = <&amx3_in1_ep>; + }; + }; + + xbar_amx3_in2_port: port@37 { + reg = <0x37>; + + xbar_amx3_in2_ep: endpoint { + remote-endpoint = <&amx3_in2_ep>; + }; + }; + + xbar_amx3_in3_port: port@38 { + reg = <0x38>; + + xbar_amx3_in3_ep: endpoint { + remote-endpoint = <&amx3_in3_ep>; + }; + }; + + xbar_amx3_in4_port: port@39 { + reg = <0x39>; + + xbar_amx3_in4_ep: endpoint { + remote-endpoint = <&amx3_in4_ep>; + }; + }; + + port@3a { + reg = <0x3a>; + + xbar_amx3_out_ep: endpoint { + remote-endpoint = <&amx3_out_ep>; + }; + }; + + xbar_amx4_in1_port: port@3b { + reg = <0x3b>; + + xbar_amx4_in1_ep: endpoint { + remote-endpoint = <&amx4_in1_ep>; + }; + }; + + xbar_amx4_in2_port: port@3c { + reg = <0x3c>; + + xbar_amx4_in2_ep: endpoint { + remote-endpoint = <&amx4_in2_ep>; + }; + }; + + xbar_amx4_in3_port: port@3d { + reg = <0x3d>; + + xbar_amx4_in3_ep: endpoint { + remote-endpoint = <&amx4_in3_ep>; + }; + }; + + xbar_amx4_in4_port: port@3e { + reg = <0x3e>; + + xbar_amx4_in4_ep: endpoint { + remote-endpoint = <&amx4_in4_ep>; + }; + }; + + port@3f { + reg = <0x3f>; + + xbar_amx4_out_ep: endpoint { + remote-endpoint = <&amx4_out_ep>; + }; + }; + + xbar_adx1_in_port: port@40 { + reg = <0x40>; + + xbar_adx1_in_ep: endpoint { + remote-endpoint = <&adx1_in_ep>; + }; + }; + + port@41 { + reg = <0x41>; + + xbar_adx1_out1_ep: endpoint { + remote-endpoint = <&adx1_out1_ep>; + }; + }; + + port@42 { + reg = <0x42>; + + xbar_adx1_out2_ep: endpoint { + remote-endpoint = <&adx1_out2_ep>; + }; + }; + + port@43 { + reg = <0x43>; + + xbar_adx1_out3_ep: endpoint { + remote-endpoint = <&adx1_out3_ep>; + }; + }; + + port@44 { + reg = <0x44>; + + xbar_adx1_out4_ep: endpoint { + remote-endpoint = <&adx1_out4_ep>; + }; + }; + + xbar_adx2_in_port: port@45 { + reg = <0x45>; + + xbar_adx2_in_ep: endpoint { + remote-endpoint = <&adx2_in_ep>; + }; + }; + + port@46 { + reg = <0x46>; + + xbar_adx2_out1_ep: endpoint { + remote-endpoint = <&adx2_out1_ep>; + }; + }; + + port@47 { + reg = <0x47>; + + xbar_adx2_out2_ep: endpoint { + remote-endpoint = <&adx2_out2_ep>; + }; + }; + + port@48 { + reg = <0x48>; + + xbar_adx2_out3_ep: endpoint { + remote-endpoint = <&adx2_out3_ep>; + }; + }; + + port@49 { + reg = <0x49>; + + xbar_adx2_out4_ep: endpoint { + remote-endpoint = <&adx2_out4_ep>; + }; + }; + + xbar_adx3_in_port: port@4a { + reg = <0x4a>; + + xbar_adx3_in_ep: endpoint { + remote-endpoint = <&adx3_in_ep>; + }; + }; + + port@4b { + reg = <0x4b>; + + xbar_adx3_out1_ep: endpoint { + remote-endpoint = <&adx3_out1_ep>; + }; + }; + + port@4c { + reg = <0x4c>; + + xbar_adx3_out2_ep: endpoint { + remote-endpoint = <&adx3_out2_ep>; + }; + }; + + port@4d { + reg = <0x4d>; + + xbar_adx3_out3_ep: endpoint { + remote-endpoint = <&adx3_out3_ep>; + }; + }; + + port@4e { + reg = <0x4e>; + + xbar_adx3_out4_ep: endpoint { + remote-endpoint = <&adx3_out4_ep>; + }; + }; + + xbar_adx4_in_port: port@4f { + reg = <0x4f>; + + xbar_adx4_in_ep: endpoint { + remote-endpoint = <&adx4_in_ep>; + }; + }; + + port@50 { + reg = <0x50>; + + xbar_adx4_out1_ep: endpoint { + remote-endpoint = <&adx4_out1_ep>; + }; + }; + + port@51 { + reg = <0x51>; + + xbar_adx4_out2_ep: endpoint { + remote-endpoint = <&adx4_out2_ep>; + }; + }; + + port@52 { + reg = <0x52>; + + xbar_adx4_out3_ep: endpoint { + remote-endpoint = <&adx4_out3_ep>; + }; + }; + + port@53 { + reg = <0x53>; + + xbar_adx4_out4_ep: endpoint { + remote-endpoint = <&adx4_out4_ep>; + }; + }; + + xbar_mixer_in1_port: port@54 { + reg = <0x54>; + + xbar_mixer_in1_ep: endpoint { + remote-endpoint = <&mixer_in1_ep>; + }; + }; + + xbar_mixer_in2_port: port@55 { + reg = <0x55>; + + xbar_mixer_in2_ep: endpoint { + remote-endpoint = <&mixer_in2_ep>; + }; + }; + + xbar_mixer_in3_port: port@56 { + reg = <0x56>; + + xbar_mixer_in3_ep: endpoint { + remote-endpoint = <&mixer_in3_ep>; + }; + }; + + xbar_mixer_in4_port: port@57 { + reg = <0x57>; + + xbar_mixer_in4_ep: endpoint { + remote-endpoint = <&mixer_in4_ep>; + }; + }; + + xbar_mixer_in5_port: port@58 { + reg = <0x58>; + + xbar_mixer_in5_ep: endpoint { + remote-endpoint = <&mixer_in5_ep>; + }; + }; + + xbar_mixer_in6_port: port@59 { + reg = <0x59>; + + xbar_mixer_in6_ep: endpoint { + remote-endpoint = <&mixer_in6_ep>; + }; + }; + + xbar_mixer_in7_port: port@5a { + reg = <0x5a>; + + xbar_mixer_in7_ep: endpoint { + remote-endpoint = <&mixer_in7_ep>; + }; + }; + + xbar_mixer_in8_port: port@5b { + reg = <0x5b>; + + xbar_mixer_in8_ep: endpoint { + remote-endpoint = <&mixer_in8_ep>; + }; + }; + + xbar_mixer_in9_port: port@5c { + reg = <0x5c>; + + xbar_mixer_in9_ep: endpoint { + remote-endpoint = <&mixer_in9_ep>; + }; + }; + + xbar_mixer_in10_port: port@5d { + reg = <0x5d>; + + xbar_mixer_in10_ep: endpoint { + remote-endpoint = <&mixer_in10_ep>; + }; + }; + + port@5e { + reg = <0x5e>; + + xbar_mixer_out1_ep: endpoint { + remote-endpoint = <&mixer_out1_ep>; + }; + }; + + port@5f { + reg = <0x5f>; + + xbar_mixer_out2_ep: endpoint { + remote-endpoint = <&mixer_out2_ep>; + }; + }; + + port@60 { + reg = <0x60>; + + xbar_mixer_out3_ep: endpoint { + remote-endpoint = <&mixer_out3_ep>; + }; + }; + + port@61 { + reg = <0x61>; + + xbar_mixer_out4_ep: endpoint { + remote-endpoint = <&mixer_out4_ep>; + }; + }; + + port@62 { + reg = <0x62>; + + xbar_mixer_out5_ep: endpoint { + remote-endpoint = <&mixer_out5_ep>; + }; + }; + }; + + admaif@290f000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + admaif0_port: port@0 { + reg = <0x0>; + + admaif0_ep: endpoint { + remote-endpoint = <&xbar_admaif0_ep>; + }; + }; + + admaif1_port: port@1 { + reg = <0x1>; + + admaif1_ep: endpoint { + remote-endpoint = <&xbar_admaif1_ep>; + }; + }; + + admaif2_port: port@2 { + reg = <0x2>; + + admaif2_ep: endpoint { + remote-endpoint = <&xbar_admaif2_ep>; + }; + }; + + admaif3_port: port@3 { + reg = <0x3>; + + admaif3_ep: endpoint { + remote-endpoint = <&xbar_admaif3_ep>; + }; + }; + + admaif4_port: port@4 { + reg = <0x4>; + + admaif4_ep: endpoint { + remote-endpoint = <&xbar_admaif4_ep>; + }; + }; + + admaif5_port: port@5 { + reg = <0x5>; + + admaif5_ep: endpoint { + remote-endpoint = <&xbar_admaif5_ep>; + }; + }; + + admaif6_port: port@6 { + reg = <0x6>; + + admaif6_ep: endpoint { + remote-endpoint = <&xbar_admaif6_ep>; + }; + }; + + admaif7_port: port@7 { + reg = <0x7>; + + admaif7_ep: endpoint { + remote-endpoint = <&xbar_admaif7_ep>; + }; + }; + + admaif8_port: port@8 { + reg = <0x8>; + + admaif8_ep: endpoint { + remote-endpoint = <&xbar_admaif8_ep>; + }; + }; + + admaif9_port: port@9 { + reg = <0x9>; + + admaif9_ep: endpoint { + remote-endpoint = <&xbar_admaif9_ep>; + }; + }; + + admaif10_port: port@a { + reg = <0xa>; + + admaif10_ep: endpoint { + remote-endpoint = <&xbar_admaif10_ep>; + }; + }; + + admaif11_port: port@b { + reg = <0xb>; + + admaif11_ep: endpoint { + remote-endpoint = <&xbar_admaif11_ep>; + }; + }; + + admaif12_port: port@c { + reg = <0xc>; + + admaif12_ep: endpoint { + remote-endpoint = <&xbar_admaif12_ep>; + }; + }; + + admaif13_port: port@d { + reg = <0xd>; + + admaif13_ep: endpoint { + remote-endpoint = <&xbar_admaif13_ep>; + }; + }; + + admaif14_port: port@e { + reg = <0xe>; + + admaif14_ep: endpoint { + remote-endpoint = <&xbar_admaif14_ep>; + }; + }; + + admaif15_port: port@f { + reg = <0xf>; + + admaif15_ep: endpoint { + remote-endpoint = <&xbar_admaif15_ep>; + }; + }; + + admaif16_port: port@10 { + reg = <0x10>; + + admaif16_ep: endpoint { + remote-endpoint = <&xbar_admaif16_ep>; + }; + }; + + admaif17_port: port@11 { + reg = <0x11>; + + admaif17_ep: endpoint { + remote-endpoint = <&xbar_admaif17_ep>; + }; + }; + + admaif18_port: port@12 { + reg = <0x12>; + + admaif18_ep: endpoint { + remote-endpoint = <&xbar_admaif18_ep>; + }; + }; + + admaif19_port: port@13 { + reg = <0x13>; + + admaif19_ep: endpoint { + remote-endpoint = <&xbar_admaif19_ep>; + }; + }; + }; + }; + + i2s@2901000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s1_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s1_ep>; + }; + }; + + i2s1_port: port@1 { + reg = <1>; + + i2s1_dap_ep: endpoint { + dai-format = "i2s"; + remote-endpoint = <&rt5658_ep>; + }; + }; + }; + }; + + i2s@2901100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s2_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s2_ep>; + }; + }; + + i2s2_port: port@1 { + reg = <1>; + + i2s2_dap_ep: endpoint { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + i2s@2901300 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s4_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s4_ep>; + }; + }; + + i2s4_port: port@1 { + reg = <1>; + + i2s4_dap_ep: endpoint { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + i2s@2901500 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s6_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s6_ep>; + }; + }; + + i2s6_port: port@1 { + reg = <1>; + + i2s6_dap_ep: endpoint@0 { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + dmic@2904200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic3_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic3_ep>; + }; + }; + + dmic3_port: port@1 { + reg = <1>; + + dmic3_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + sfc@2902000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc1_in_ep>; + }; + }; + + sfc1_out_port: port@1 { + reg = <1>; + + sfc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc1_out_ep>; + }; + }; + }; + }; + + sfc@2902200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc2_in_ep>; + }; + }; + + sfc2_out_port: port@1 { + reg = <1>; + + sfc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc2_out_ep>; + }; + }; + }; + }; + + sfc@2902400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc3_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc3_in_ep>; + }; + }; + + sfc3_out_port: port@1 { + reg = <1>; + + sfc3_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc3_out_ep>; + }; + }; + }; + }; + + sfc@2902600 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc4_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc4_in_ep>; + }; + }; + + sfc4_out_port: port@1 { + reg = <1>; + + sfc4_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc4_out_ep>; + }; + }; + }; + }; + + mvc@290a000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc1_in_ep>; + }; + }; + + mvc1_out_port: port@1 { + reg = <1>; + + mvc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc1_out_ep>; + }; + }; + }; + }; + + mvc@290a200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc2_in_ep>; + }; + }; + + mvc2_out_port: port@1 { + reg = <1>; + + mvc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc2_out_ep>; + }; + }; + }; + }; + + amx@2903000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx1_in1_ep: endpoint { + remote-endpoint = <&xbar_amx1_in1_ep>; + }; + }; + + port@1 { + reg = <1>; + + amx1_in2_ep: endpoint { + remote-endpoint = <&xbar_amx1_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx1_in3_ep: endpoint { + remote-endpoint = <&xbar_amx1_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx1_in4_ep: endpoint { + remote-endpoint = <&xbar_amx1_in4_ep>; + }; + }; + + amx1_out_port: port@4 { + reg = <4>; + + amx1_out_ep: endpoint { + remote-endpoint = <&xbar_amx1_out_ep>; + }; + }; + }; };
- admaif@290f000 { + amx@2903100 { status = "okay";
ports { #address-cells = <1>; #size-cells = <0>;
- admaif0_port: port@0 { - reg = <0x0>; + port@0 { + reg = <0>;
- admaif0_ep: endpoint { - remote-endpoint = <&xbar_admaif0_ep>; + amx2_in1_ep: endpoint { + remote-endpoint = <&xbar_amx2_in1_ep>; }; };
- admaif1_port: port@1 { - reg = <0x1>; + port@1 { + reg = <1>;
- admaif1_ep: endpoint { - remote-endpoint = <&xbar_admaif1_ep>; + amx2_in2_ep: endpoint { + remote-endpoint = <&xbar_amx2_in2_ep>; }; };
- admaif2_port: port@2 { - reg = <0x2>; + amx2_in3_port: port@2 { + reg = <2>;
- admaif2_ep: endpoint { - remote-endpoint = <&xbar_admaif2_ep>; + amx2_in3_ep: endpoint { + remote-endpoint = <&xbar_amx2_in3_ep>; }; };
- admaif3_port: port@3 { - reg = <0x3>; + amx2_in4_port: port@3 { + reg = <3>;
- admaif3_ep: endpoint { - remote-endpoint = <&xbar_admaif3_ep>; + amx2_in4_ep: endpoint { + remote-endpoint = <&xbar_amx2_in4_ep>; }; };
- admaif4_port: port@4 { - reg = <0x4>; + amx2_out_port: port@4 { + reg = <4>;
- admaif4_ep: endpoint { - remote-endpoint = <&xbar_admaif4_ep>; + amx2_out_ep: endpoint { + remote-endpoint = <&xbar_amx2_out_ep>; }; }; + }; + };
- admaif5_port: port@5 { - reg = <0x5>; + amx@2903200 { + status = "okay";
- admaif5_ep: endpoint { - remote-endpoint = <&xbar_admaif5_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx3_in1_ep: endpoint { + remote-endpoint = <&xbar_amx3_in1_ep>; }; };
- admaif6_port: port@6 { - reg = <0x6>; + port@1 { + reg = <1>;
- admaif6_ep: endpoint { - remote-endpoint = <&xbar_admaif6_ep>; + amx3_in2_ep: endpoint { + remote-endpoint = <&xbar_amx3_in2_ep>; }; };
- admaif7_port: port@7 { - reg = <0x7>; + port@2 { + reg = <2>;
- admaif7_ep: endpoint { - remote-endpoint = <&xbar_admaif7_ep>; + amx3_in3_ep: endpoint { + remote-endpoint = <&xbar_amx3_in3_ep>; }; };
- admaif8_port: port@8 { - reg = <0x8>; + port@3 { + reg = <3>;
- admaif8_ep: endpoint { - remote-endpoint = <&xbar_admaif8_ep>; + amx3_in4_ep: endpoint { + remote-endpoint = <&xbar_amx3_in4_ep>; }; };
- admaif9_port: port@9 { - reg = <0x9>; + amx3_out_port: port@4 { + reg = <4>;
- admaif9_ep: endpoint { - remote-endpoint = <&xbar_admaif9_ep>; + amx3_out_ep: endpoint { + remote-endpoint = <&xbar_amx3_out_ep>; }; }; + }; + };
- admaif10_port: port@a { - reg = <0xa>; + amx@2903300 { + status = "okay";
- admaif10_ep: endpoint { - remote-endpoint = <&xbar_admaif10_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx4_in1_ep: endpoint { + remote-endpoint = <&xbar_amx4_in1_ep>; }; };
- admaif11_port: port@b { - reg = <0xb>; + port@1 { + reg = <1>;
- admaif11_ep: endpoint { - remote-endpoint = <&xbar_admaif11_ep>; + amx4_in2_ep: endpoint { + remote-endpoint = <&xbar_amx4_in2_ep>; }; };
- admaif12_port: port@c { - reg = <0xc>; + port@2 { + reg = <2>;
- admaif12_ep: endpoint { - remote-endpoint = <&xbar_admaif12_ep>; + amx4_in3_ep: endpoint { + remote-endpoint = <&xbar_amx4_in3_ep>; }; };
- admaif13_port: port@d { - reg = <0xd>; + port@3 { + reg = <3>;
- admaif13_ep: endpoint { - remote-endpoint = <&xbar_admaif13_ep>; + amx4_in4_ep: endpoint { + remote-endpoint = <&xbar_amx4_in4_ep>; }; };
- admaif14_port: port@e { - reg = <0xe>; + amx4_out_port: port@4 { + reg = <4>;
- admaif14_ep: endpoint { - remote-endpoint = <&xbar_admaif14_ep>; + amx4_out_ep: endpoint { + remote-endpoint = <&xbar_amx4_out_ep>; }; }; + }; + };
- admaif15_port: port@f { - reg = <0xf>; + adx@2903800 { + status = "okay";
- admaif15_ep: endpoint { - remote-endpoint = <&xbar_admaif15_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adx1_in_ep: endpoint { + remote-endpoint = <&xbar_adx1_in_ep>; }; };
- admaif16_port: port@10 { - reg = <0x10>; + adx1_out1_port: port@1 { + reg = <1>;
- admaif16_ep: endpoint { - remote-endpoint = <&xbar_admaif16_ep>; + adx1_out1_ep: endpoint { + remote-endpoint = <&xbar_adx1_out1_ep>; }; };
- admaif17_port: port@11 { - reg = <0x11>; + adx1_out2_port: port@2 { + reg = <2>;
- admaif17_ep: endpoint { - remote-endpoint = <&xbar_admaif17_ep>; + adx1_out2_ep: endpoint { + remote-endpoint = <&xbar_adx1_out2_ep>; }; };
- admaif18_port: port@12 { - reg = <0x12>; + adx1_out3_port: port@3 { + reg = <3>;
- admaif18_ep: endpoint { - remote-endpoint = <&xbar_admaif18_ep>; + adx1_out3_ep: endpoint { + remote-endpoint = <&xbar_adx1_out3_ep>; }; };
- admaif19_port: port@13 { - reg = <0x13>; + adx1_out4_port: port@4 { + reg = <4>;
- admaif19_ep: endpoint { - remote-endpoint = <&xbar_admaif19_ep>; + adx1_out4_ep: endpoint { + remote-endpoint = <&xbar_adx1_out4_ep>; }; }; }; };
- i2s@2901000 { + adx@2903900 { status = "okay";
ports { @@ -409,49 +1469,46 @@ port@0 { reg = <0>;
- i2s1_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s1_ep>; + adx2_in_ep: endpoint { + remote-endpoint = <&xbar_adx2_in_ep>; }; };
- i2s1_port: port@1 { + adx2_out1_port: port@1 { reg = <1>;
- i2s1_dap_ep: endpoint { - dai-format = "i2s"; - remote-endpoint = <&rt5658_ep>; + adx2_out1_ep: endpoint { + remote-endpoint = <&xbar_adx2_out1_ep>; }; }; - }; - };
- i2s@2901100 { - status = "okay"; + adx2_out2_port: port@2 { + reg = <2>;
- ports { - #address-cells = <1>; - #size-cells = <0>; + adx2_out2_ep: endpoint { + remote-endpoint = <&xbar_adx2_out2_ep>; + }; + };
- port@0 { - reg = <0>; + adx2_out3_port: port@3 { + reg = <3>;
- i2s2_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s2_ep>; + adx2_out3_ep: endpoint { + remote-endpoint = <&xbar_adx2_out3_ep>; }; };
- i2s2_port: port@1 { - reg = <1>; + adx2_out4_port: port@4 { + reg = <4>;
- i2s2_dap_ep: endpoint { - dai-format = "i2s"; - /* Place holder for external Codec */ + adx2_out4_ep: endpoint { + remote-endpoint = <&xbar_adx2_out4_ep>; }; }; }; };
- i2s@2901300 { + adx@2903a00 { status = "okay";
ports { @@ -461,23 +1518,46 @@ port@0 { reg = <0>;
- i2s4_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s4_ep>; + adx3_in_ep: endpoint { + remote-endpoint = <&xbar_adx3_in_ep>; }; };
- i2s4_port: port@1 { + adx3_out1_port: port@1 { reg = <1>;
- i2s4_dap_ep: endpoint { - dai-format = "i2s"; - /* Place holder for external Codec */ + adx3_out1_ep: endpoint { + remote-endpoint = <&xbar_adx3_out1_ep>; + }; + }; + + adx3_out2_port: port@2 { + reg = <2>; + + adx3_out2_ep: endpoint { + remote-endpoint = <&xbar_adx3_out2_ep>; + }; + }; + + adx3_out3_port: port@3 { + reg = <3>; + + adx3_out3_ep: endpoint { + remote-endpoint = <&xbar_adx3_out3_ep>; + }; + }; + + adx3_out4_port: port@4 { + reg = <4>; + + adx3_out4_ep: endpoint { + remote-endpoint = <&xbar_adx3_out4_ep>; }; }; }; };
- i2s@2901500 { + adx@2903b00 { status = "okay";
ports { @@ -487,23 +1567,46 @@ port@0 { reg = <0>;
- i2s6_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s6_ep>; + adx4_in_ep: endpoint { + remote-endpoint = <&xbar_adx4_in_ep>; }; };
- i2s6_port: port@1 { + adx4_out1_port: port@1 { reg = <1>;
- i2s6_dap_ep: endpoint@0 { - dai-format = "i2s"; - /* Place holder for external Codec */ + adx4_out1_ep: endpoint { + remote-endpoint = <&xbar_adx4_out1_ep>; + }; + }; + + adx4_out2_port: port@2 { + reg = <2>; + + adx4_out2_ep: endpoint { + remote-endpoint = <&xbar_adx4_out2_ep>; + }; + }; + + adx4_out3_port: port@3 { + reg = <3>; + + adx4_out3_ep: endpoint { + remote-endpoint = <&xbar_adx4_out3_ep>; + }; + }; + + adx4_out4_port: port@4 { + reg = <4>; + + adx4_out4_ep: endpoint { + remote-endpoint = <&xbar_adx4_out4_ep>; }; }; }; };
- dmic@2904200 { + amixer@290bb00 { status = "okay";
ports { @@ -511,18 +1614,122 @@ #size-cells = <0>;
port@0 { - reg = <0>; + reg = <0x0>;
- dmic3_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic3_ep>; + mixer_in1_ep: endpoint { + remote-endpoint = <&xbar_mixer_in1_ep>; }; };
- dmic3_port: port@1 { - reg = <1>; + port@1 { + reg = <0x1>;
- dmic3_dap_ep: endpoint { - /* Place holder for external Codec */ + mixer_in2_ep: endpoint { + remote-endpoint = <&xbar_mixer_in2_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + mixer_in3_ep: endpoint { + remote-endpoint = <&xbar_mixer_in3_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + mixer_in4_ep: endpoint { + remote-endpoint = <&xbar_mixer_in4_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + mixer_in5_ep: endpoint { + remote-endpoint = <&xbar_mixer_in5_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + mixer_in6_ep: endpoint { + remote-endpoint = <&xbar_mixer_in6_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + mixer_in7_ep: endpoint { + remote-endpoint = <&xbar_mixer_in7_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + mixer_in8_ep: endpoint { + remote-endpoint = <&xbar_mixer_in8_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + mixer_in9_ep: endpoint { + remote-endpoint = <&xbar_mixer_in9_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + mixer_in10_ep: endpoint { + remote-endpoint = <&xbar_mixer_in10_ep>; + }; + }; + + mixer_out1_port: port@a { + reg = <0xa>; + + mixer_out1_ep: endpoint { + remote-endpoint = <&xbar_mixer_out1_ep>; + }; + }; + + mixer_out2_port: port@b { + reg = <0xb>; + + mixer_out2_ep: endpoint { + remote-endpoint = <&xbar_mixer_out2_ep>; + }; + }; + + mixer_out3_port: port@c { + reg = <0xc>; + + mixer_out3_ep: endpoint { + remote-endpoint = <&xbar_mixer_out3_ep>; + }; + }; + + mixer_out4_port: port@d { + reg = <0xd>; + + mixer_out4_ep: endpoint { + remote-endpoint = <&xbar_mixer_out4_ep>; + }; + }; + + mixer_out5_port: port@e { + reg = <0xe>; + + mixer_out5_ep: endpoint { + remote-endpoint = <&xbar_mixer_out5_ep>; }; }; }; @@ -827,6 +2034,40 @@ /* XBAR Ports */ <&xbar_i2s1_port>, <&xbar_i2s2_port>, <&xbar_i2s4_port>, <&xbar_i2s6_port>, <&xbar_dmic3_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>, + <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>, + <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>, + <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_adx3_in_port>, <&xbar_adx4_in_port>, + <&xbar_mixer_in1_port>, <&xbar_mixer_in2_port>, + <&xbar_mixer_in3_port>, <&xbar_mixer_in4_port>, + <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>, + <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>, + <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&amx3_out_port>, <&amx4_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&adx3_out1_port>, <&adx3_out2_port>, + <&adx3_out3_port>, <&adx3_out4_port>, + <&adx4_out1_port>, <&adx4_out2_port>, + <&adx4_out3_port>, <&adx4_out4_port>, + <&mixer_out1_port>, <&mixer_out2_port>, <&mixer_out3_port>, + <&mixer_out4_port>, <&mixer_out5_port>, /* BE I/O Ports */ <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>, <&dmic3_port>; diff --git a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi index 836a7e0..48fc9cf 100644 --- a/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi @@ -238,178 +238,1190 @@ remote-endpoint = <&dspk2_cif_ep>; }; }; + + xbar_sfc1_in_port: port@20 { + reg = <0x20>; + + xbar_sfc1_in_ep: endpoint { + remote-endpoint = <&sfc1_cif_in_ep>; + }; + }; + + port@21 { + reg = <0x21>; + + xbar_sfc1_out_ep: endpoint { + remote-endpoint = <&sfc1_cif_out_ep>; + }; + }; + + xbar_sfc2_in_port: port@22 { + reg = <0x22>; + + xbar_sfc2_in_ep: endpoint { + remote-endpoint = <&sfc2_cif_in_ep>; + }; + }; + + port@23 { + reg = <0x23>; + + xbar_sfc2_out_ep: endpoint { + remote-endpoint = <&sfc2_cif_out_ep>; + }; + }; + + xbar_sfc3_in_port: port@24 { + reg = <0x24>; + + xbar_sfc3_in_ep: endpoint { + remote-endpoint = <&sfc3_cif_in_ep>; + }; + }; + + port@25 { + reg = <0x25>; + + xbar_sfc3_out_ep: endpoint { + remote-endpoint = <&sfc3_cif_out_ep>; + }; + }; + + xbar_sfc4_in_port: port@26 { + reg = <0x26>; + + xbar_sfc4_in_ep: endpoint { + remote-endpoint = <&sfc4_cif_in_ep>; + }; + }; + + port@27 { + reg = <0x27>; + + xbar_sfc4_out_ep: endpoint { + remote-endpoint = <&sfc4_cif_out_ep>; + }; + }; + + xbar_mvc1_in_port: port@28 { + reg = <0x28>; + + xbar_mvc1_in_ep: endpoint { + remote-endpoint = <&mvc1_cif_in_ep>; + }; + }; + + port@29 { + reg = <0x29>; + + xbar_mvc1_out_ep: endpoint { + remote-endpoint = <&mvc1_cif_out_ep>; + }; + }; + + xbar_mvc2_in_port: port@2a { + reg = <0x2a>; + + xbar_mvc2_in_ep: endpoint { + remote-endpoint = <&mvc2_cif_in_ep>; + }; + }; + + port@2b { + reg = <0x2b>; + + xbar_mvc2_out_ep: endpoint { + remote-endpoint = <&mvc2_cif_out_ep>; + }; + }; + + xbar_amx1_in1_port: port@2c { + reg = <0x2c>; + + xbar_amx1_in1_ep: endpoint { + remote-endpoint = <&amx1_in1_ep>; + }; + }; + + xbar_amx1_in2_port: port@2d { + reg = <0x2d>; + + xbar_amx1_in2_ep: endpoint { + remote-endpoint = <&amx1_in2_ep>; + }; + }; + + xbar_amx1_in3_port: port@2e { + reg = <0x2e>; + + xbar_amx1_in3_ep: endpoint { + remote-endpoint = <&amx1_in3_ep>; + }; + }; + + xbar_amx1_in4_port: port@2f { + reg = <0x2f>; + + xbar_amx1_in4_ep: endpoint { + remote-endpoint = <&amx1_in4_ep>; + }; + }; + + port@30 { + reg = <0x30>; + + xbar_amx1_out_ep: endpoint { + remote-endpoint = <&amx1_out_ep>; + }; + }; + + xbar_amx2_in1_port: port@31 { + reg = <0x31>; + + xbar_amx2_in1_ep: endpoint { + remote-endpoint = <&amx2_in1_ep>; + }; + }; + + xbar_amx2_in2_port: port@32 { + reg = <0x32>; + + xbar_amx2_in2_ep: endpoint { + remote-endpoint = <&amx2_in2_ep>; + }; + }; + + xbar_amx2_in3_port: port@33 { + reg = <0x33>; + + xbar_amx2_in3_ep: endpoint { + remote-endpoint = <&amx2_in3_ep>; + }; + }; + + xbar_amx2_in4_port: port@34 { + reg = <0x34>; + + xbar_amx2_in4_ep: endpoint { + remote-endpoint = <&amx2_in4_ep>; + }; + }; + + port@35 { + reg = <0x35>; + + xbar_amx2_out_ep: endpoint { + remote-endpoint = <&amx2_out_ep>; + }; + }; + + xbar_amx3_in1_port: port@36 { + reg = <0x36>; + + xbar_amx3_in1_ep: endpoint { + remote-endpoint = <&amx3_in1_ep>; + }; + }; + + xbar_amx3_in2_port: port@37 { + reg = <0x37>; + + xbar_amx3_in2_ep: endpoint { + remote-endpoint = <&amx3_in2_ep>; + }; + }; + + xbar_amx3_in3_port: port@38 { + reg = <0x38>; + + xbar_amx3_in3_ep: endpoint { + remote-endpoint = <&amx3_in3_ep>; + }; + }; + + xbar_amx3_in4_port: port@39 { + reg = <0x39>; + + xbar_amx3_in4_ep: endpoint { + remote-endpoint = <&amx3_in4_ep>; + }; + }; + + port@3a { + reg = <0x3a>; + + xbar_amx3_out_ep: endpoint { + remote-endpoint = <&amx3_out_ep>; + }; + }; + + xbar_amx4_in1_port: port@3b { + reg = <0x3b>; + + xbar_amx4_in1_ep: endpoint { + remote-endpoint = <&amx4_in1_ep>; + }; + }; + + xbar_amx4_in2_port: port@3c { + reg = <0x3c>; + + xbar_amx4_in2_ep: endpoint { + remote-endpoint = <&amx4_in2_ep>; + }; + }; + + xbar_amx4_in3_port: port@3d { + reg = <0x3d>; + + xbar_amx4_in3_ep: endpoint { + remote-endpoint = <&amx4_in3_ep>; + }; + }; + + xbar_amx4_in4_port: port@3e { + reg = <0x3e>; + + xbar_amx4_in4_ep: endpoint { + remote-endpoint = <&amx4_in4_ep>; + }; + }; + + port@3f { + reg = <0x3f>; + + xbar_amx4_out_ep: endpoint { + remote-endpoint = <&amx4_out_ep>; + }; + }; + + xbar_adx1_in_port: port@40 { + reg = <0x40>; + + xbar_adx1_in_ep: endpoint { + remote-endpoint = <&adx1_in_ep>; + }; + }; + + port@41 { + reg = <0x41>; + + xbar_adx1_out1_ep: endpoint { + remote-endpoint = <&adx1_out1_ep>; + }; + }; + + port@42 { + reg = <0x42>; + + xbar_adx1_out2_ep: endpoint { + remote-endpoint = <&adx1_out2_ep>; + }; + }; + + port@43 { + reg = <0x43>; + + xbar_adx1_out3_ep: endpoint { + remote-endpoint = <&adx1_out3_ep>; + }; + }; + + port@44 { + reg = <0x44>; + + xbar_adx1_out4_ep: endpoint { + remote-endpoint = <&adx1_out4_ep>; + }; + }; + + xbar_adx2_in_port: port@45 { + reg = <0x45>; + + xbar_adx2_in_ep: endpoint { + remote-endpoint = <&adx2_in_ep>; + }; + }; + + port@46 { + reg = <0x46>; + + xbar_adx2_out1_ep: endpoint { + remote-endpoint = <&adx2_out1_ep>; + }; + }; + + port@47 { + reg = <0x47>; + + xbar_adx2_out2_ep: endpoint { + remote-endpoint = <&adx2_out2_ep>; + }; + }; + + port@48 { + reg = <0x48>; + + xbar_adx2_out3_ep: endpoint { + remote-endpoint = <&adx2_out3_ep>; + }; + }; + + port@49 { + reg = <0x49>; + + xbar_adx2_out4_ep: endpoint { + remote-endpoint = <&adx2_out4_ep>; + }; + }; + + xbar_adx3_in_port: port@4a { + reg = <0x4a>; + + xbar_adx3_in_ep: endpoint { + remote-endpoint = <&adx3_in_ep>; + }; + }; + + port@4b { + reg = <0x4b>; + + xbar_adx3_out1_ep: endpoint { + remote-endpoint = <&adx3_out1_ep>; + }; + }; + + port@4c { + reg = <0x4c>; + + xbar_adx3_out2_ep: endpoint { + remote-endpoint = <&adx3_out2_ep>; + }; + }; + + port@4d { + reg = <0x4d>; + + xbar_adx3_out3_ep: endpoint { + remote-endpoint = <&adx3_out3_ep>; + }; + }; + + port@4e { + reg = <0x4e>; + + xbar_adx3_out4_ep: endpoint { + remote-endpoint = <&adx3_out4_ep>; + }; + }; + + xbar_adx4_in_port: port@4f { + reg = <0x4f>; + + xbar_adx4_in_ep: endpoint { + remote-endpoint = <&adx4_in_ep>; + }; + }; + + port@50 { + reg = <0x50>; + + xbar_adx4_out1_ep: endpoint { + remote-endpoint = <&adx4_out1_ep>; + }; + }; + + port@51 { + reg = <0x51>; + + xbar_adx4_out2_ep: endpoint { + remote-endpoint = <&adx4_out2_ep>; + }; + }; + + port@52 { + reg = <0x52>; + + xbar_adx4_out3_ep: endpoint { + remote-endpoint = <&adx4_out3_ep>; + }; + }; + + port@53 { + reg = <0x53>; + + xbar_adx4_out4_ep: endpoint { + remote-endpoint = <&adx4_out4_ep>; + }; + }; + + xbar_mixer_in1_port: port@54 { + reg = <0x54>; + + xbar_mixer_in1_ep: endpoint { + remote-endpoint = <&mixer_in1_ep>; + }; + }; + + xbar_mixer_in2_port: port@55 { + reg = <0x55>; + + xbar_mixer_in2_ep: endpoint { + remote-endpoint = <&mixer_in2_ep>; + }; + }; + + xbar_mixer_in3_port: port@56 { + reg = <0x56>; + + xbar_mixer_in3_ep: endpoint { + remote-endpoint = <&mixer_in3_ep>; + }; + }; + + xbar_mixer_in4_port: port@57 { + reg = <0x57>; + + xbar_mixer_in4_ep: endpoint { + remote-endpoint = <&mixer_in4_ep>; + }; + }; + + xbar_mixer_in5_port: port@58 { + reg = <0x58>; + + xbar_mixer_in5_ep: endpoint { + remote-endpoint = <&mixer_in5_ep>; + }; + }; + + xbar_mixer_in6_port: port@59 { + reg = <0x59>; + + xbar_mixer_in6_ep: endpoint { + remote-endpoint = <&mixer_in6_ep>; + }; + }; + + xbar_mixer_in7_port: port@5a { + reg = <0x5a>; + + xbar_mixer_in7_ep: endpoint { + remote-endpoint = <&mixer_in7_ep>; + }; + }; + + xbar_mixer_in8_port: port@5b { + reg = <0x5b>; + + xbar_mixer_in8_ep: endpoint { + remote-endpoint = <&mixer_in8_ep>; + }; + }; + + xbar_mixer_in9_port: port@5c { + reg = <0x5c>; + + xbar_mixer_in9_ep: endpoint { + remote-endpoint = <&mixer_in9_ep>; + }; + }; + + xbar_mixer_in10_port: port@5d { + reg = <0x5d>; + + xbar_mixer_in10_ep: endpoint { + remote-endpoint = <&mixer_in10_ep>; + }; + }; + + port@5e { + reg = <0x5e>; + + xbar_mixer_out1_ep: endpoint { + remote-endpoint = <&mixer_out1_ep>; + }; + }; + + port@5f { + reg = <0x5f>; + + xbar_mixer_out2_ep: endpoint { + remote-endpoint = <&mixer_out2_ep>; + }; + }; + + port@60 { + reg = <0x60>; + + xbar_mixer_out3_ep: endpoint { + remote-endpoint = <&mixer_out3_ep>; + }; + }; + + port@61 { + reg = <0x61>; + + xbar_mixer_out4_ep: endpoint { + remote-endpoint = <&mixer_out4_ep>; + }; + }; + + port@62 { + reg = <0x62>; + + xbar_mixer_out5_ep: endpoint { + remote-endpoint = <&mixer_out5_ep>; + }; + }; + }; + + admaif@290f000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + admaif0_port: port@0 { + reg = <0x0>; + + admaif0_ep: endpoint { + remote-endpoint = <&xbar_admaif0_ep>; + }; + }; + + admaif1_port: port@1 { + reg = <0x1>; + + admaif1_ep: endpoint { + remote-endpoint = <&xbar_admaif1_ep>; + }; + }; + + admaif2_port: port@2 { + reg = <0x2>; + + admaif2_ep: endpoint { + remote-endpoint = <&xbar_admaif2_ep>; + }; + }; + + admaif3_port: port@3 { + reg = <0x3>; + + admaif3_ep: endpoint { + remote-endpoint = <&xbar_admaif3_ep>; + }; + }; + + admaif4_port: port@4 { + reg = <0x4>; + + admaif4_ep: endpoint { + remote-endpoint = <&xbar_admaif4_ep>; + }; + }; + + admaif5_port: port@5 { + reg = <0x5>; + + admaif5_ep: endpoint { + remote-endpoint = <&xbar_admaif5_ep>; + }; + }; + + admaif6_port: port@6 { + reg = <0x6>; + + admaif6_ep: endpoint { + remote-endpoint = <&xbar_admaif6_ep>; + }; + }; + + admaif7_port: port@7 { + reg = <0x7>; + + admaif7_ep: endpoint { + remote-endpoint = <&xbar_admaif7_ep>; + }; + }; + + admaif8_port: port@8 { + reg = <0x8>; + + admaif8_ep: endpoint { + remote-endpoint = <&xbar_admaif8_ep>; + }; + }; + + admaif9_port: port@9 { + reg = <0x9>; + + admaif9_ep: endpoint { + remote-endpoint = <&xbar_admaif9_ep>; + }; + }; + + admaif10_port: port@a { + reg = <0xa>; + + admaif10_ep: endpoint { + remote-endpoint = <&xbar_admaif10_ep>; + }; + }; + + admaif11_port: port@b { + reg = <0xb>; + + admaif11_ep: endpoint { + remote-endpoint = <&xbar_admaif11_ep>; + }; + }; + + admaif12_port: port@c { + reg = <0xc>; + + admaif12_ep: endpoint { + remote-endpoint = <&xbar_admaif12_ep>; + }; + }; + + admaif13_port: port@d { + reg = <0xd>; + + admaif13_ep: endpoint { + remote-endpoint = <&xbar_admaif13_ep>; + }; + }; + + admaif14_port: port@e { + reg = <0xe>; + + admaif14_ep: endpoint { + remote-endpoint = <&xbar_admaif14_ep>; + }; + }; + + admaif15_port: port@f { + reg = <0xf>; + + admaif15_ep: endpoint { + remote-endpoint = <&xbar_admaif15_ep>; + }; + }; + + admaif16_port: port@10 { + reg = <0x10>; + + admaif16_ep: endpoint { + remote-endpoint = <&xbar_admaif16_ep>; + }; + }; + + admaif17_port: port@11 { + reg = <0x11>; + + admaif17_ep: endpoint { + remote-endpoint = <&xbar_admaif17_ep>; + }; + }; + + admaif18_port: port@12 { + reg = <0x12>; + + admaif18_ep: endpoint { + remote-endpoint = <&xbar_admaif18_ep>; + }; + }; + + admaif19_port: port@13 { + reg = <0x13>; + + admaif19_ep: endpoint { + remote-endpoint = <&xbar_admaif19_ep>; + }; + }; + }; + }; + + i2s@2901200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s3_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s3_ep>; + }; + }; + + i2s3_port: port@1 { + reg = <1>; + + i2s3_dap_ep: endpoint { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; + }; + + i2s@2901400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + i2s5_cif_ep: endpoint { + remote-endpoint = <&xbar_i2s5_ep>; + }; + }; + + i2s5_port: port@1 { + reg = <1>; + + i2s5_dap_ep: endpoint@0 { + dai-format = "i2s"; + /* Place holder for external Codec */ + }; + }; + }; };
- admaif@290f000 { + dmic@2904000 { status = "okay";
ports { #address-cells = <1>; #size-cells = <0>;
- admaif0_port: port@0 { - reg = <0x0>; + port@0 { + reg = <0>;
- admaif0_ep: endpoint { - remote-endpoint = <&xbar_admaif0_ep>; + dmic1_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic1_ep>; }; };
- admaif1_port: port@1 { - reg = <0x1>; + dmic1_port: port@1 { + reg = <1>;
- admaif1_ep: endpoint { - remote-endpoint = <&xbar_admaif1_ep>; + dmic1_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif2_port: port@2 { - reg = <0x2>; + dmic@2904100 { + status = "okay";
- admaif2_ep: endpoint { - remote-endpoint = <&xbar_admaif2_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic2_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic2_ep>; }; };
- admaif3_port: port@3 { - reg = <0x3>; + dmic2_port: port@1 { + reg = <1>;
- admaif3_ep: endpoint { - remote-endpoint = <&xbar_admaif3_ep>; + dmic2_dap_ep: endpoint { + /* Place holder for external Codec */ }; }; + }; + };
- admaif4_port: port@4 { - reg = <0x4>; + dmic@2904300 { + status = "okay";
- admaif4_ep: endpoint { - remote-endpoint = <&xbar_admaif4_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dmic4_cif_ep: endpoint { + remote-endpoint = <&xbar_dmic4_ep>; + }; + }; + + dmic4_port: port@1 { + reg = <1>; + + dmic4_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dspk@2905000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk1_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk1_ep>; + }; + }; + + dspk1_port: port@1 { + reg = <1>; + + dspk1_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + dspk@2905100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dspk2_cif_ep: endpoint { + remote-endpoint = <&xbar_dspk2_ep>; + }; + }; + + dspk2_port: port@1 { + reg = <1>; + + dspk2_dap_ep: endpoint { + /* Place holder for external Codec */ + }; + }; + }; + }; + + sfc@2902000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc1_in_ep>; + convert-rate = <44100>; + }; + }; + + sfc1_out_port: port@1 { + reg = <1>; + + sfc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc1_out_ep>; + convert-rate = <48000>; + }; + }; + }; + }; + + sfc@2902200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc2_in_ep>; + }; + }; + + sfc2_out_port: port@1 { + reg = <1>; + + sfc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc2_out_ep>; + }; + }; + }; + }; + + sfc@2902400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc3_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc3_in_ep>; + }; + }; + + sfc3_out_port: port@1 { + reg = <1>; + + sfc3_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc3_out_ep>; + }; + }; + }; + }; + + sfc@2902600 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc4_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc4_in_ep>; + }; + }; + + sfc4_out_port: port@1 { + reg = <1>; + + sfc4_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc4_out_ep>; + }; + }; + }; + }; + + mvc@290a000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc1_in_ep>; + }; + }; + + mvc1_out_port: port@1 { + reg = <1>; + + mvc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc1_out_ep>; + }; + }; + }; + }; + + mvc@290a200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc2_in_ep>; + }; + }; + + mvc2_out_port: port@1 { + reg = <1>; + + mvc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc2_out_ep>; + }; + }; + }; + }; + + amx@2903000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx1_in1_ep: endpoint { + remote-endpoint = <&xbar_amx1_in1_ep>; }; };
- admaif5_port: port@5 { - reg = <0x5>; + port@1 { + reg = <1>;
- admaif5_ep: endpoint { - remote-endpoint = <&xbar_admaif5_ep>; + amx1_in2_ep: endpoint { + remote-endpoint = <&xbar_amx1_in2_ep>; }; };
- admaif6_port: port@6 { - reg = <0x6>; + port@2 { + reg = <2>;
- admaif6_ep: endpoint { - remote-endpoint = <&xbar_admaif6_ep>; + amx1_in3_ep: endpoint { + remote-endpoint = <&xbar_amx1_in3_ep>; }; };
- admaif7_port: port@7 { - reg = <0x7>; + port@3 { + reg = <3>;
- admaif7_ep: endpoint { - remote-endpoint = <&xbar_admaif7_ep>; + amx1_in4_ep: endpoint { + remote-endpoint = <&xbar_amx1_in4_ep>; }; };
- admaif8_port: port@8 { - reg = <0x8>; + amx1_out_port: port@4 { + reg = <4>;
- admaif8_ep: endpoint { - remote-endpoint = <&xbar_admaif8_ep>; + amx1_out_ep: endpoint { + remote-endpoint = <&xbar_amx1_out_ep>; }; }; + }; + };
- admaif9_port: port@9 { - reg = <0x9>; + amx@2903100 { + status = "okay";
- admaif9_ep: endpoint { - remote-endpoint = <&xbar_admaif9_ep>; - }; - }; + ports { + #address-cells = <1>; + #size-cells = <0>;
- admaif10_port: port@a { - reg = <0xa>; + port@0 { + reg = <0>;
- admaif10_ep: endpoint { - remote-endpoint = <&xbar_admaif10_ep>; + amx2_in1_ep: endpoint { + remote-endpoint = <&xbar_amx2_in1_ep>; }; };
- admaif11_port: port@b { - reg = <0xb>; + port@1 { + reg = <1>;
- admaif11_ep: endpoint { - remote-endpoint = <&xbar_admaif11_ep>; + amx2_in2_ep: endpoint { + remote-endpoint = <&xbar_amx2_in2_ep>; }; };
- admaif12_port: port@c { - reg = <0xc>; + amx2_in3_port: port@2 { + reg = <2>;
- admaif12_ep: endpoint { - remote-endpoint = <&xbar_admaif12_ep>; + amx2_in3_ep: endpoint { + remote-endpoint = <&xbar_amx2_in3_ep>; }; };
- admaif13_port: port@d { - reg = <0xd>; + amx2_in4_port: port@3 { + reg = <3>;
- admaif13_ep: endpoint { - remote-endpoint = <&xbar_admaif13_ep>; + amx2_in4_ep: endpoint { + remote-endpoint = <&xbar_amx2_in4_ep>; }; };
- admaif14_port: port@e { - reg = <0xe>; + amx2_out_port: port@4 { + reg = <4>;
- admaif14_ep: endpoint { - remote-endpoint = <&xbar_admaif14_ep>; + amx2_out_ep: endpoint { + remote-endpoint = <&xbar_amx2_out_ep>; }; }; + }; + };
- admaif15_port: port@f { - reg = <0xf>; + amx@2903200 { + status = "okay";
- admaif15_ep: endpoint { - remote-endpoint = <&xbar_admaif15_ep>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx3_in1_ep: endpoint { + remote-endpoint = <&xbar_amx3_in1_ep>; }; };
- admaif16_port: port@10 { - reg = <0x10>; + port@1 { + reg = <1>;
- admaif16_ep: endpoint { - remote-endpoint = <&xbar_admaif16_ep>; + amx3_in2_ep: endpoint { + remote-endpoint = <&xbar_amx3_in2_ep>; }; };
- admaif17_port: port@11 { - reg = <0x11>; + port@2 { + reg = <2>;
- admaif17_ep: endpoint { - remote-endpoint = <&xbar_admaif17_ep>; + amx3_in3_ep: endpoint { + remote-endpoint = <&xbar_amx3_in3_ep>; }; };
- admaif18_port: port@12 { - reg = <0x12>; + port@3 { + reg = <3>;
- admaif18_ep: endpoint { - remote-endpoint = <&xbar_admaif18_ep>; + amx3_in4_ep: endpoint { + remote-endpoint = <&xbar_amx3_in4_ep>; }; };
- admaif19_port: port@13 { - reg = <0x13>; + amx3_out_port: port@4 { + reg = <4>;
- admaif19_ep: endpoint { - remote-endpoint = <&xbar_admaif19_ep>; + amx3_out_ep: endpoint { + remote-endpoint = <&xbar_amx3_out_ep>; }; }; }; };
- i2s@2901200 { + amx@2903300 { status = "okay";
ports { @@ -419,49 +1431,46 @@ port@0 { reg = <0>;
- i2s3_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s3_ep>; + amx4_in1_ep: endpoint { + remote-endpoint = <&xbar_amx4_in1_ep>; }; };
- i2s3_port: port@1 { + port@1 { reg = <1>;
- i2s3_dap_ep: endpoint { - dai-format = "i2s"; - /* Place holder for external Codec */ + amx4_in2_ep: endpoint { + remote-endpoint = <&xbar_amx4_in2_ep>; }; }; - }; - };
- i2s@2901400 { - status = "okay"; + port@2 { + reg = <2>;
- ports { - #address-cells = <1>; - #size-cells = <0>; + amx4_in3_ep: endpoint { + remote-endpoint = <&xbar_amx4_in3_ep>; + }; + };
- port@0 { - reg = <0>; + port@3 { + reg = <3>;
- i2s5_cif_ep: endpoint { - remote-endpoint = <&xbar_i2s5_ep>; + amx4_in4_ep: endpoint { + remote-endpoint = <&xbar_amx4_in4_ep>; }; };
- i2s5_port: port@1 { - reg = <1>; + amx4_out_port: port@4 { + reg = <4>;
- i2s5_dap_ep: endpoint@0 { - dai-format = "i2s"; - /* Place holder for external Codec */ + amx4_out_ep: endpoint { + remote-endpoint = <&xbar_amx4_out_ep>; }; }; }; };
- dmic@2904000 { + adx@2903800 { status = "okay";
ports { @@ -471,22 +1480,46 @@ port@0 { reg = <0>;
- dmic1_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic1_ep>; + adx1_in_ep: endpoint { + remote-endpoint = <&xbar_adx1_in_ep>; }; };
- dmic1_port: port@1 { + adx1_out1_port: port@1 { reg = <1>;
- dmic1_dap_ep: endpoint { - /* Place holder for external Codec */ + adx1_out1_ep: endpoint { + remote-endpoint = <&xbar_adx1_out1_ep>; + }; + }; + + adx1_out2_port: port@2 { + reg = <2>; + + adx1_out2_ep: endpoint { + remote-endpoint = <&xbar_adx1_out2_ep>; + }; + }; + + adx1_out3_port: port@3 { + reg = <3>; + + adx1_out3_ep: endpoint { + remote-endpoint = <&xbar_adx1_out3_ep>; + }; + }; + + adx1_out4_port: port@4 { + reg = <4>; + + adx1_out4_ep: endpoint { + remote-endpoint = <&xbar_adx1_out4_ep>; }; }; }; };
- dmic@2904100 { + adx@2903900 { status = "okay";
ports { @@ -496,22 +1529,46 @@ port@0 { reg = <0>;
- dmic2_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic2_ep>; + adx2_in_ep: endpoint { + remote-endpoint = <&xbar_adx2_in_ep>; }; };
- dmic2_port: port@1 { + adx2_out1_port: port@1 { reg = <1>;
- dmic2_dap_ep: endpoint { - /* Place holder for external Codec */ + adx2_out1_ep: endpoint { + remote-endpoint = <&xbar_adx2_out1_ep>; + }; + }; + + adx2_out2_port: port@2 { + reg = <2>; + + adx2_out2_ep: endpoint { + remote-endpoint = <&xbar_adx2_out2_ep>; + }; + }; + + adx2_out3_port: port@3 { + reg = <3>; + + adx2_out3_ep: endpoint { + remote-endpoint = <&xbar_adx2_out3_ep>; + }; + }; + + adx2_out4_port: port@4 { + reg = <4>; + + adx2_out4_ep: endpoint { + remote-endpoint = <&xbar_adx2_out4_ep>; }; }; }; };
- dmic@2904300 { + adx@2903a00 { status = "okay";
ports { @@ -521,22 +1578,46 @@ port@0 { reg = <0>;
- dmic4_cif_ep: endpoint { - remote-endpoint = <&xbar_dmic4_ep>; + adx3_in_ep: endpoint { + remote-endpoint = <&xbar_adx3_in_ep>; }; };
- dmic4_port: port@1 { + adx3_out1_port: port@1 { reg = <1>;
- dmic4_dap_ep: endpoint { - /* Place holder for external Codec */ + adx3_out1_ep: endpoint { + remote-endpoint = <&xbar_adx3_out1_ep>; + }; + }; + + adx3_out2_port: port@2 { + reg = <2>; + + adx3_out2_ep: endpoint { + remote-endpoint = <&xbar_adx3_out2_ep>; + }; + }; + + adx3_out3_port: port@3 { + reg = <3>; + + adx3_out3_ep: endpoint { + remote-endpoint = <&xbar_adx3_out3_ep>; + }; + }; + + adx3_out4_port: port@4 { + reg = <4>; + + adx3_out4_ep: endpoint { + remote-endpoint = <&xbar_adx3_out4_ep>; }; }; }; };
- dspk@2905000 { + adx@2903b00 { status = "okay";
ports { @@ -546,22 +1627,46 @@ port@0 { reg = <0>;
- dspk1_cif_ep: endpoint { - remote-endpoint = <&xbar_dspk1_ep>; + adx4_in_ep: endpoint { + remote-endpoint = <&xbar_adx4_in_ep>; }; };
- dspk1_port: port@1 { + adx4_out1_port: port@1 { reg = <1>;
- dspk1_dap_ep: endpoint { - /* Place holder for external Codec */ + adx4_out1_ep: endpoint { + remote-endpoint = <&xbar_adx4_out1_ep>; + }; + }; + + adx4_out2_port: port@2 { + reg = <2>; + + adx4_out2_ep: endpoint { + remote-endpoint = <&xbar_adx4_out2_ep>; + }; + }; + + adx4_out3_port: port@3 { + reg = <3>; + + adx4_out3_ep: endpoint { + remote-endpoint = <&xbar_adx4_out3_ep>; + }; + }; + + adx4_out4_port: port@4 { + reg = <4>; + + adx4_out4_ep: endpoint { + remote-endpoint = <&xbar_adx4_out4_ep>; }; }; }; };
- dspk@2905100 { + amixer@290bb00 { status = "okay";
ports { @@ -569,18 +1674,122 @@ #size-cells = <0>;
port@0 { - reg = <0>; + reg = <0x0>;
- dspk2_cif_ep: endpoint { - remote-endpoint = <&xbar_dspk2_ep>; + mixer_in1_ep: endpoint { + remote-endpoint = <&xbar_mixer_in1_ep>; }; };
- dspk2_port: port@1 { - reg = <1>; + port@1 { + reg = <0x1>;
- dspk2_dap_ep: endpoint { - /* Place holder for external Codec */ + mixer_in2_ep: endpoint { + remote-endpoint = <&xbar_mixer_in2_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + mixer_in3_ep: endpoint { + remote-endpoint = <&xbar_mixer_in3_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + mixer_in4_ep: endpoint { + remote-endpoint = <&xbar_mixer_in4_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + mixer_in5_ep: endpoint { + remote-endpoint = <&xbar_mixer_in5_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + mixer_in6_ep: endpoint { + remote-endpoint = <&xbar_mixer_in6_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + mixer_in7_ep: endpoint { + remote-endpoint = <&xbar_mixer_in7_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + mixer_in8_ep: endpoint { + remote-endpoint = <&xbar_mixer_in8_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + mixer_in9_ep: endpoint { + remote-endpoint = <&xbar_mixer_in9_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + mixer_in10_ep: endpoint { + remote-endpoint = <&xbar_mixer_in10_ep>; + }; + }; + + mixer_out1_port: port@a { + reg = <0xa>; + + mixer_out1_ep: endpoint { + remote-endpoint = <&xbar_mixer_out1_ep>; + }; + }; + + mixer_out2_port: port@b { + reg = <0xb>; + + mixer_out2_ep: endpoint { + remote-endpoint = <&xbar_mixer_out2_ep>; + }; + }; + + mixer_out3_port: port@c { + reg = <0xc>; + + mixer_out3_ep: endpoint { + remote-endpoint = <&xbar_mixer_out3_ep>; + }; + }; + + mixer_out4_port: port@d { + reg = <0xd>; + + mixer_out4_ep: endpoint { + remote-endpoint = <&xbar_mixer_out4_ep>; + }; + }; + + mixer_out5_port: port@e { + reg = <0xe>; + + mixer_out5_ep: endpoint { + remote-endpoint = <&xbar_mixer_out5_ep>; }; }; }; @@ -850,6 +2059,41 @@ <&xbar_i2s3_port>, <&xbar_i2s5_port>, <&xbar_dmic1_port>, <&xbar_dmic2_port>, <&xbar_dmic4_port>, <&xbar_dspk1_port>, <&xbar_dspk2_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>, + <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>, + <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>, + <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_adx3_in_port>, <&xbar_adx4_in_port>, + <&xbar_mixer_in1_port>, <&xbar_mixer_in2_port>, + <&xbar_mixer_in3_port>, <&xbar_mixer_in4_port>, + <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>, + <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>, + <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&amx3_out_port>, <&amx4_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&adx3_out1_port>, <&adx3_out2_port>, + <&adx3_out3_port>, <&adx3_out4_port>, + <&adx4_out1_port>, <&adx4_out2_port>, + <&adx4_out3_port>, <&adx4_out4_port>, + <&mixer_out1_port>, <&mixer_out2_port>, + <&mixer_out3_port>, <&mixer_out4_port>, + <&mixer_out5_port>, /* BE I/O Ports */ <&i2s3_port>, <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic4_port>, diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts index 7d3e363..2e17df6 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts @@ -339,6 +339,481 @@ }; };
+ sfc@702d2000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc1_in_ep>; + }; + }; + + sfc1_out_port: port@1 { + reg = <1>; + + sfc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc1_out_ep>; + }; + }; + }; + }; + + sfc@702d2200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc2_in_ep>; + }; + }; + + sfc2_out_port: port@1 { + reg = <1>; + + sfc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc2_out_ep>; + }; + }; + }; + }; + + sfc@702d2400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc3_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc3_in_ep>; + }; + }; + + sfc3_out_port: port@1 { + reg = <1>; + + sfc3_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc3_out_ep>; + }; + }; + }; + }; + + sfc@702d2600 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc4_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc4_in_ep>; + }; + }; + + sfc4_out_port: port@1 { + reg = <1>; + + sfc4_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc4_out_ep>; + }; + }; + }; + }; + + mvc@702da000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc1_in_ep>; + }; + }; + + mvc1_out_port: port@1 { + reg = <1>; + + mvc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc1_out_ep>; + }; + }; + }; + }; + + mvc@702da200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc2_in_ep>; + }; + }; + + mvc2_out_port: port@1 { + reg = <1>; + + mvc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc2_out_ep>; + }; + }; + }; + }; + + amx@702d3000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx1_in1_ep: endpoint { + remote-endpoint = <&xbar_amx1_in1_ep>; + }; + }; + + port@1 { + reg = <1>; + + amx1_in2_ep: endpoint { + remote-endpoint = <&xbar_amx1_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx1_in3_ep: endpoint { + remote-endpoint = <&xbar_amx1_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx1_in4_ep: endpoint { + remote-endpoint = <&xbar_amx1_in4_ep>; + }; + }; + + amx1_out_port: port@4 { + reg = <4>; + + amx1_out_ep: endpoint { + remote-endpoint = <&xbar_amx1_out_ep>; + }; + }; + }; + }; + + amx@702d3100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx2_in1_ep: endpoint { + remote-endpoint = <&xbar_amx2_in1_ep>; + }; + }; + + port@1 { + reg = <1>; + + amx2_in2_ep: endpoint { + remote-endpoint = <&xbar_amx2_in2_ep>; + }; + }; + + amx2_in3_port: port@2 { + reg = <2>; + + amx2_in3_ep: endpoint { + remote-endpoint = <&xbar_amx2_in3_ep>; + }; + }; + + amx2_in4_port: port@3 { + reg = <3>; + + amx2_in4_ep: endpoint { + remote-endpoint = <&xbar_amx2_in4_ep>; + }; + }; + + amx2_out_port: port@4 { + reg = <4>; + + amx2_out_ep: endpoint { + remote-endpoint = <&xbar_amx2_out_ep>; + }; + }; + }; + }; + + adx@702d3800 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adx1_in_ep: endpoint { + remote-endpoint = <&xbar_adx1_in_ep>; + }; + }; + + adx1_out1_port: port@1 { + reg = <1>; + + adx1_out1_ep: endpoint { + remote-endpoint = <&xbar_adx1_out1_ep>; + }; + }; + + adx1_out2_port: port@2 { + reg = <2>; + + adx1_out2_ep: endpoint { + remote-endpoint = <&xbar_adx1_out2_ep>; + }; + }; + + adx1_out3_port: port@3 { + reg = <3>; + + adx1_out3_ep: endpoint { + remote-endpoint = <&xbar_adx1_out3_ep>; + }; + }; + + adx1_out4_port: port@4 { + reg = <4>; + + adx1_out4_ep: endpoint { + remote-endpoint = <&xbar_adx1_out4_ep>; + }; + }; + }; + }; + + adx@702d3900 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adx2_in_ep: endpoint { + remote-endpoint = <&xbar_adx2_in_ep>; + }; + }; + + adx2_out1_port: port@1 { + reg = <1>; + + adx2_out1_ep: endpoint { + remote-endpoint = <&xbar_adx2_out1_ep>; + }; + }; + + adx2_out2_port: port@2 { + reg = <2>; + + adx2_out2_ep: endpoint { + remote-endpoint = <&xbar_adx2_out2_ep>; + }; + }; + + adx2_out3_port: port@3 { + reg = <3>; + + adx2_out3_ep: endpoint { + remote-endpoint = <&xbar_adx2_out3_ep>; + }; + }; + + adx2_out4_port: port@4 { + reg = <4>; + + adx2_out4_ep: endpoint { + remote-endpoint = <&xbar_adx2_out4_ep>; + }; + }; + }; + }; + + amixer@702dbb00 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0x0>; + + mixer_in1_ep: endpoint { + remote-endpoint = <&xbar_mixer_in1_ep>; + }; + }; + + port@1 { + reg = <0x1>; + + mixer_in2_ep: endpoint { + remote-endpoint = <&xbar_mixer_in2_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + mixer_in3_ep: endpoint { + remote-endpoint = <&xbar_mixer_in3_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + mixer_in4_ep: endpoint { + remote-endpoint = <&xbar_mixer_in4_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + mixer_in5_ep: endpoint { + remote-endpoint = <&xbar_mixer_in5_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + mixer_in6_ep: endpoint { + remote-endpoint = <&xbar_mixer_in6_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + mixer_in7_ep: endpoint { + remote-endpoint = <&xbar_mixer_in7_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + mixer_in8_ep: endpoint { + remote-endpoint = <&xbar_mixer_in8_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + mixer_in9_ep: endpoint { + remote-endpoint = <&xbar_mixer_in9_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + mixer_in10_ep: endpoint { + remote-endpoint = <&xbar_mixer_in10_ep>; + }; + }; + + mixer_out1_port: port@a { + reg = <0xa>; + + mixer_out1_ep: endpoint { + remote-endpoint = <&xbar_mixer_out1_ep>; + }; + }; + + mixer_out2_port: port@b { + reg = <0xb>; + + mixer_out2_ep: endpoint { + remote-endpoint = <&xbar_mixer_out2_ep>; + }; + }; + + mixer_out3_port: port@c { + reg = <0xc>; + + mixer_out3_ep: endpoint { + remote-endpoint = <&xbar_mixer_out3_ep>; + }; + }; + + mixer_out4_port: port@d { + reg = <0xd>; + + mixer_out4_ep: endpoint { + remote-endpoint = <&xbar_mixer_out4_ep>; + }; + }; + + mixer_out5_port: port@e { + reg = <0xe>; + + mixer_out5_ep: endpoint { + remote-endpoint = <&xbar_mixer_out5_ep>; + }; + }; + }; + }; + ports { xbar_i2s1_port: port@a { reg = <0xa>; @@ -403,6 +878,382 @@ remote-endpoint = <&dmic3_cif_ep>; }; }; + + xbar_sfc1_in_port: port@12 { + reg = <0x12>; + + xbar_sfc1_in_ep: endpoint { + remote-endpoint = <&sfc1_cif_in_ep>; + }; + }; + + port@13 { + reg = <0x13>; + + xbar_sfc1_out_ep: endpoint { + remote-endpoint = <&sfc1_cif_out_ep>; + }; + }; + + xbar_sfc2_in_port: port@14 { + reg = <0x14>; + + xbar_sfc2_in_ep: endpoint { + remote-endpoint = <&sfc2_cif_in_ep>; + }; + }; + + port@15 { + reg = <0x15>; + + xbar_sfc2_out_ep: endpoint { + remote-endpoint = <&sfc2_cif_out_ep>; + }; + }; + + xbar_sfc3_in_port: port@16 { + reg = <0x16>; + + xbar_sfc3_in_ep: endpoint { + remote-endpoint = <&sfc3_cif_in_ep>; + }; + }; + + port@17 { + reg = <0x17>; + + xbar_sfc3_out_ep: endpoint { + remote-endpoint = <&sfc3_cif_out_ep>; + }; + }; + + xbar_sfc4_in_port: port@18 { + reg = <0x18>; + + xbar_sfc4_in_ep: endpoint { + remote-endpoint = <&sfc4_cif_in_ep>; + }; + }; + + port@19 { + reg = <0x19>; + + xbar_sfc4_out_ep: endpoint { + remote-endpoint = <&sfc4_cif_out_ep>; + }; + }; + + xbar_mvc1_in_port: port@1a { + reg = <0x1a>; + + xbar_mvc1_in_ep: endpoint { + remote-endpoint = <&mvc1_cif_in_ep>; + }; + }; + + port@1b { + reg = <0x1b>; + + xbar_mvc1_out_ep: endpoint { + remote-endpoint = <&mvc1_cif_out_ep>; + }; + }; + + xbar_mvc2_in_port: port@1c { + reg = <0x1c>; + + xbar_mvc2_in_ep: endpoint { + remote-endpoint = <&mvc2_cif_in_ep>; + }; + }; + + port@1d { + reg = <0x1d>; + + xbar_mvc2_out_ep: endpoint { + remote-endpoint = <&mvc2_cif_out_ep>; + }; + }; + + xbar_amx1_in1_port: port@1e { + reg = <0x1e>; + + xbar_amx1_in1_ep: endpoint { + remote-endpoint = <&amx1_in1_ep>; + }; + }; + + xbar_amx1_in2_port: port@1f { + reg = <0x1f>; + + xbar_amx1_in2_ep: endpoint { + remote-endpoint = <&amx1_in2_ep>; + }; + }; + + xbar_amx1_in3_port: port@20 { + reg = <0x20>; + + xbar_amx1_in3_ep: endpoint { + remote-endpoint = <&amx1_in3_ep>; + }; + }; + + xbar_amx1_in4_port: port@21 { + reg = <0x21>; + + xbar_amx1_in4_ep: endpoint { + remote-endpoint = <&amx1_in4_ep>; + }; + }; + + port@22 { + reg = <0x22>; + + xbar_amx1_out_ep: endpoint { + remote-endpoint = <&amx1_out_ep>; + }; + }; + + xbar_amx2_in1_port: port@23 { + reg = <0x23>; + + xbar_amx2_in1_ep: endpoint { + remote-endpoint = <&amx2_in1_ep>; + }; + }; + + xbar_amx2_in2_port: port@24 { + reg = <0x24>; + + xbar_amx2_in2_ep: endpoint { + remote-endpoint = <&amx2_in2_ep>; + }; + }; + + xbar_amx2_in3_port: port@25 { + reg = <0x25>; + + xbar_amx2_in3_ep: endpoint { + remote-endpoint = <&amx2_in3_ep>; + }; + }; + + xbar_amx2_in4_port: port@26 { + reg = <0x26>; + + xbar_amx2_in4_ep: endpoint { + remote-endpoint = <&amx2_in4_ep>; + }; + }; + + port@27 { + reg = <0x27>; + + xbar_amx2_out_ep: endpoint { + remote-endpoint = <&amx2_out_ep>; + }; + }; + + xbar_adx1_in_port: port@28 { + reg = <0x28>; + + xbar_adx1_in_ep: endpoint { + remote-endpoint = <&adx1_in_ep>; + }; + }; + + port@29 { + reg = <0x29>; + + xbar_adx1_out1_ep: endpoint { + remote-endpoint = <&adx1_out1_ep>; + }; + }; + + port@2a { + reg = <0x2a>; + + xbar_adx1_out2_ep: endpoint { + remote-endpoint = <&adx1_out2_ep>; + }; + }; + + port@2b { + reg = <0x2b>; + + xbar_adx1_out3_ep: endpoint { + remote-endpoint = <&adx1_out3_ep>; + }; + }; + + port@2c { + reg = <0x2c>; + + xbar_adx1_out4_ep: endpoint { + remote-endpoint = <&adx1_out4_ep>; + }; + }; + + xbar_adx2_in_port: port@2d { + reg = <0x2d>; + + xbar_adx2_in_ep: endpoint { + remote-endpoint = <&adx2_in_ep>; + }; + }; + + port@2e { + reg = <0x2e>; + + xbar_adx2_out1_ep: endpoint { + remote-endpoint = <&adx2_out1_ep>; + }; + }; + + port@2f { + reg = <0x2f>; + + xbar_adx2_out2_ep: endpoint { + remote-endpoint = <&adx2_out2_ep>; + }; + }; + + port@30 { + reg = <0x30>; + + xbar_adx2_out3_ep: endpoint { + remote-endpoint = <&adx2_out3_ep>; + }; + }; + + port@31 { + reg = <0x31>; + + xbar_adx2_out4_ep: endpoint { + remote-endpoint = <&adx2_out4_ep>; + }; + }; + + xbar_mixer_in1_port: port@32 { + reg = <0x32>; + + xbar_mixer_in1_ep: endpoint { + remote-endpoint = <&mixer_in1_ep>; + }; + }; + + xbar_mixer_in2_port: port@33 { + reg = <0x33>; + + xbar_mixer_in2_ep: endpoint { + remote-endpoint = <&mixer_in2_ep>; + }; + }; + + xbar_mixer_in3_port: port@34 { + reg = <0x34>; + + xbar_mixer_in3_ep: endpoint { + remote-endpoint = <&mixer_in3_ep>; + }; + }; + + xbar_mixer_in4_port: port@35 { + reg = <0x35>; + + xbar_mixer_in4_ep: endpoint { + remote-endpoint = <&mixer_in4_ep>; + }; + }; + + xbar_mixer_in5_port: port@36 { + reg = <0x36>; + + xbar_mixer_in5_ep: endpoint { + remote-endpoint = <&mixer_in5_ep>; + }; + }; + + xbar_mixer_in6_port: port@37 { + reg = <0x37>; + + xbar_mixer_in6_ep: endpoint { + remote-endpoint = <&mixer_in6_ep>; + }; + }; + + xbar_mixer_in7_port: port@38 { + reg = <0x38>; + + xbar_mixer_in7_ep: endpoint { + remote-endpoint = <&mixer_in7_ep>; + }; + }; + + xbar_mixer_in8_port: port@39 { + reg = <0x39>; + + xbar_mixer_in8_ep: endpoint { + remote-endpoint = <&mixer_in8_ep>; + }; + }; + + xbar_mixer_in9_port: port@3a { + reg = <0x3a>; + + xbar_mixer_in9_ep: endpoint { + remote-endpoint = <&mixer_in9_ep>; + }; + }; + + xbar_mixer_in10_port: port@3b { + reg = <0x3b>; + + xbar_mixer_in10_ep: endpoint { + remote-endpoint = <&mixer_in10_ep>; + }; + }; + + port@3c { + reg = <0x3c>; + + xbar_mixer_out1_ep: endpoint { + remote-endpoint = <&mixer_out1_ep>; + }; + }; + + port@3d { + reg = <0x3d>; + + xbar_mixer_out2_ep: endpoint { + remote-endpoint = <&mixer_out2_ep>; + }; + }; + + port@3e { + reg = <0x3e>; + + xbar_mixer_out3_ep: endpoint { + remote-endpoint = <&mixer_out3_ep>; + }; + }; + + port@3f { + reg = <0x3f>; + + xbar_mixer_out4_ep: endpoint { + remote-endpoint = <&mixer_out4_ep>; + }; + }; + + port@40 { + reg = <0x40>; + + xbar_mixer_out5_ep: endpoint { + remote-endpoint = <&mixer_out5_ep>; + }; + }; }; }; }; @@ -420,6 +1271,31 @@ <&xbar_i2s1_port>, <&xbar_i2s2_port>, <&xbar_i2s3_port>, <&xbar_i2s4_port>, <&xbar_i2s5_port>, <&xbar_dmic1_port>, <&xbar_dmic2_port>, <&xbar_dmic3_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_mixer_in1_port>, <&xbar_mixer_in2_port>, + <&xbar_mixer_in3_port>, <&xbar_mixer_in4_port>, + <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>, + <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>, + <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&mixer_out1_port>, <&mixer_out2_port>, + <&mixer_out3_port>, <&mixer_out4_port>, + <&mixer_out5_port>, /* I/O DAP Ports */ <&i2s1_port>, <&i2s2_port>, <&i2s3_port>, <&i2s4_port>, <&i2s5_port>, <&dmic1_port>, <&dmic2_port>, <&dmic3_port>; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts index 7dbb13f..030f264 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts @@ -746,6 +746,481 @@ }; };
+ sfc@702d2000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc1_in_ep>; + }; + }; + + sfc1_out_port: port@1 { + reg = <1>; + + sfc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc1_out_ep>; + }; + }; + }; + }; + + sfc@702d2200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc2_in_ep>; + }; + }; + + sfc2_out_port: port@1 { + reg = <1>; + + sfc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc2_out_ep>; + }; + }; + }; + }; + + sfc@702d2400 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc3_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc3_in_ep>; + }; + }; + + sfc3_out_port: port@1 { + reg = <1>; + + sfc3_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc3_out_ep>; + }; + }; + }; + }; + + sfc@702d2600 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sfc4_cif_in_ep: endpoint { + remote-endpoint = <&xbar_sfc4_in_ep>; + }; + }; + + sfc4_out_port: port@1 { + reg = <1>; + + sfc4_cif_out_ep: endpoint { + remote-endpoint = <&xbar_sfc4_out_ep>; + }; + }; + }; + }; + + mvc@702da000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc1_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc1_in_ep>; + }; + }; + + mvc1_out_port: port@1 { + reg = <1>; + + mvc1_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc1_out_ep>; + }; + }; + }; + }; + + mvc@702da200 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mvc2_cif_in_ep: endpoint { + remote-endpoint = <&xbar_mvc2_in_ep>; + }; + }; + + mvc2_out_port: port@1 { + reg = <1>; + + mvc2_cif_out_ep: endpoint { + remote-endpoint = <&xbar_mvc2_out_ep>; + }; + }; + }; + }; + + amx@702d3000 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx1_in1_ep: endpoint { + remote-endpoint = <&xbar_amx1_in1_ep>; + }; + }; + + port@1 { + reg = <1>; + + amx1_in2_ep: endpoint { + remote-endpoint = <&xbar_amx1_in2_ep>; + }; + }; + + port@2 { + reg = <2>; + + amx1_in3_ep: endpoint { + remote-endpoint = <&xbar_amx1_in3_ep>; + }; + }; + + port@3 { + reg = <3>; + + amx1_in4_ep: endpoint { + remote-endpoint = <&xbar_amx1_in4_ep>; + }; + }; + + amx1_out_port: port@4 { + reg = <4>; + + amx1_out_ep: endpoint { + remote-endpoint = <&xbar_amx1_out_ep>; + }; + }; + }; + }; + + amx@702d3100 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + amx2_in1_ep: endpoint { + remote-endpoint = <&xbar_amx2_in1_ep>; + }; + }; + + port@1 { + reg = <1>; + + amx2_in2_ep: endpoint { + remote-endpoint = <&xbar_amx2_in2_ep>; + }; + }; + + amx2_in3_port: port@2 { + reg = <2>; + + amx2_in3_ep: endpoint { + remote-endpoint = <&xbar_amx2_in3_ep>; + }; + }; + + amx2_in4_port: port@3 { + reg = <3>; + + amx2_in4_ep: endpoint { + remote-endpoint = <&xbar_amx2_in4_ep>; + }; + }; + + amx2_out_port: port@4 { + reg = <4>; + + amx2_out_ep: endpoint { + remote-endpoint = <&xbar_amx2_out_ep>; + }; + }; + }; + }; + + adx@702d3800 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adx1_in_ep: endpoint { + remote-endpoint = <&xbar_adx1_in_ep>; + }; + }; + + adx1_out1_port: port@1 { + reg = <1>; + + adx1_out1_ep: endpoint { + remote-endpoint = <&xbar_adx1_out1_ep>; + }; + }; + + adx1_out2_port: port@2 { + reg = <2>; + + adx1_out2_ep: endpoint { + remote-endpoint = <&xbar_adx1_out2_ep>; + }; + }; + + adx1_out3_port: port@3 { + reg = <3>; + + adx1_out3_ep: endpoint { + remote-endpoint = <&xbar_adx1_out3_ep>; + }; + }; + + adx1_out4_port: port@4 { + reg = <4>; + + adx1_out4_ep: endpoint { + remote-endpoint = <&xbar_adx1_out4_ep>; + }; + }; + }; + }; + + adx@702d3900 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adx2_in_ep: endpoint { + remote-endpoint = <&xbar_adx2_in_ep>; + }; + }; + + adx2_out1_port: port@1 { + reg = <1>; + + adx2_out1_ep: endpoint { + remote-endpoint = <&xbar_adx2_out1_ep>; + }; + }; + + adx2_out2_port: port@2 { + reg = <2>; + + adx2_out2_ep: endpoint { + remote-endpoint = <&xbar_adx2_out2_ep>; + }; + }; + + adx2_out3_port: port@3 { + reg = <3>; + + adx2_out3_ep: endpoint { + remote-endpoint = <&xbar_adx2_out3_ep>; + }; + }; + + adx2_out4_port: port@4 { + reg = <4>; + + adx2_out4_ep: endpoint { + remote-endpoint = <&xbar_adx2_out4_ep>; + }; + }; + }; + }; + + amixer@702dbb00 { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0x0>; + + mixer_in1_ep: endpoint { + remote-endpoint = <&xbar_mixer_in1_ep>; + }; + }; + + port@1 { + reg = <0x1>; + + mixer_in2_ep: endpoint { + remote-endpoint = <&xbar_mixer_in2_ep>; + }; + }; + + port@2 { + reg = <0x2>; + + mixer_in3_ep: endpoint { + remote-endpoint = <&xbar_mixer_in3_ep>; + }; + }; + + port@3 { + reg = <0x3>; + + mixer_in4_ep: endpoint { + remote-endpoint = <&xbar_mixer_in4_ep>; + }; + }; + + port@4 { + reg = <0x4>; + + mixer_in5_ep: endpoint { + remote-endpoint = <&xbar_mixer_in5_ep>; + }; + }; + + port@5 { + reg = <0x5>; + + mixer_in6_ep: endpoint { + remote-endpoint = <&xbar_mixer_in6_ep>; + }; + }; + + port@6 { + reg = <0x6>; + + mixer_in7_ep: endpoint { + remote-endpoint = <&xbar_mixer_in7_ep>; + }; + }; + + port@7 { + reg = <0x7>; + + mixer_in8_ep: endpoint { + remote-endpoint = <&xbar_mixer_in8_ep>; + }; + }; + + port@8 { + reg = <0x8>; + + mixer_in9_ep: endpoint { + remote-endpoint = <&xbar_mixer_in9_ep>; + }; + }; + + port@9 { + reg = <0x9>; + + mixer_in10_ep: endpoint { + remote-endpoint = <&xbar_mixer_in10_ep>; + }; + }; + + mixer_out1_port: port@a { + reg = <0xa>; + + mixer_out1_ep: endpoint { + remote-endpoint = <&xbar_mixer_out1_ep>; + }; + }; + + mixer_out2_port: port@b { + reg = <0xb>; + + mixer_out2_ep: endpoint { + remote-endpoint = <&xbar_mixer_out2_ep>; + }; + }; + + mixer_out3_port: port@c { + reg = <0xc>; + + mixer_out3_ep: endpoint { + remote-endpoint = <&xbar_mixer_out3_ep>; + }; + }; + + mixer_out4_port: port@d { + reg = <0xd>; + + mixer_out4_ep: endpoint { + remote-endpoint = <&xbar_mixer_out4_ep>; + }; + }; + + mixer_out5_port: port@e { + reg = <0xe>; + + mixer_out5_ep: endpoint { + remote-endpoint = <&xbar_mixer_out5_ep>; + }; + }; + }; + }; + ports { xbar_i2s3_port: port@c { reg = <0xc>; @@ -778,6 +1253,382 @@ remote-endpoint = <&dmic2_cif_ep>; }; }; + + xbar_sfc1_in_port: port@12 { + reg = <0x12>; + + xbar_sfc1_in_ep: endpoint { + remote-endpoint = <&sfc1_cif_in_ep>; + }; + }; + + port@13 { + reg = <0x13>; + + xbar_sfc1_out_ep: endpoint { + remote-endpoint = <&sfc1_cif_out_ep>; + }; + }; + + xbar_sfc2_in_port: port@14 { + reg = <0x14>; + + xbar_sfc2_in_ep: endpoint { + remote-endpoint = <&sfc2_cif_in_ep>; + }; + }; + + port@15 { + reg = <0x15>; + + xbar_sfc2_out_ep: endpoint { + remote-endpoint = <&sfc2_cif_out_ep>; + }; + }; + + xbar_sfc3_in_port: port@16 { + reg = <0x16>; + + xbar_sfc3_in_ep: endpoint { + remote-endpoint = <&sfc3_cif_in_ep>; + }; + }; + + port@17 { + reg = <0x17>; + + xbar_sfc3_out_ep: endpoint { + remote-endpoint = <&sfc3_cif_out_ep>; + }; + }; + + xbar_sfc4_in_port: port@18 { + reg = <0x18>; + + xbar_sfc4_in_ep: endpoint { + remote-endpoint = <&sfc4_cif_in_ep>; + }; + }; + + port@19 { + reg = <0x19>; + + xbar_sfc4_out_ep: endpoint { + remote-endpoint = <&sfc4_cif_out_ep>; + }; + }; + + xbar_mvc1_in_port: port@1a { + reg = <0x1a>; + + xbar_mvc1_in_ep: endpoint { + remote-endpoint = <&mvc1_cif_in_ep>; + }; + }; + + port@1b { + reg = <0x1b>; + + xbar_mvc1_out_ep: endpoint { + remote-endpoint = <&mvc1_cif_out_ep>; + }; + }; + + xbar_mvc2_in_port: port@1c { + reg = <0x1c>; + + xbar_mvc2_in_ep: endpoint { + remote-endpoint = <&mvc2_cif_in_ep>; + }; + }; + + port@1d { + reg = <0x1d>; + + xbar_mvc2_out_ep: endpoint { + remote-endpoint = <&mvc2_cif_out_ep>; + }; + }; + + xbar_amx1_in1_port: port@1e { + reg = <0x1e>; + + xbar_amx1_in1_ep: endpoint { + remote-endpoint = <&amx1_in1_ep>; + }; + }; + + xbar_amx1_in2_port: port@1f { + reg = <0x1f>; + + xbar_amx1_in2_ep: endpoint { + remote-endpoint = <&amx1_in2_ep>; + }; + }; + + xbar_amx1_in3_port: port@20 { + reg = <0x20>; + + xbar_amx1_in3_ep: endpoint { + remote-endpoint = <&amx1_in3_ep>; + }; + }; + + xbar_amx1_in4_port: port@21 { + reg = <0x21>; + + xbar_amx1_in4_ep: endpoint { + remote-endpoint = <&amx1_in4_ep>; + }; + }; + + port@22 { + reg = <0x22>; + + xbar_amx1_out_ep: endpoint { + remote-endpoint = <&amx1_out_ep>; + }; + }; + + xbar_amx2_in1_port: port@23 { + reg = <0x23>; + + xbar_amx2_in1_ep: endpoint { + remote-endpoint = <&amx2_in1_ep>; + }; + }; + + xbar_amx2_in2_port: port@24 { + reg = <0x24>; + + xbar_amx2_in2_ep: endpoint { + remote-endpoint = <&amx2_in2_ep>; + }; + }; + + xbar_amx2_in3_port: port@25 { + reg = <0x25>; + + xbar_amx2_in3_ep: endpoint { + remote-endpoint = <&amx2_in3_ep>; + }; + }; + + xbar_amx2_in4_port: port@26 { + reg = <0x26>; + + xbar_amx2_in4_ep: endpoint { + remote-endpoint = <&amx2_in4_ep>; + }; + }; + + port@27 { + reg = <0x27>; + + xbar_amx2_out_ep: endpoint { + remote-endpoint = <&amx2_out_ep>; + }; + }; + + xbar_adx1_in_port: port@28 { + reg = <0x28>; + + xbar_adx1_in_ep: endpoint { + remote-endpoint = <&adx1_in_ep>; + }; + }; + + port@29 { + reg = <0x29>; + + xbar_adx1_out1_ep: endpoint { + remote-endpoint = <&adx1_out1_ep>; + }; + }; + + port@2a { + reg = <0x2a>; + + xbar_adx1_out2_ep: endpoint { + remote-endpoint = <&adx1_out2_ep>; + }; + }; + + port@2b { + reg = <0x2b>; + + xbar_adx1_out3_ep: endpoint { + remote-endpoint = <&adx1_out3_ep>; + }; + }; + + port@2c { + reg = <0x2c>; + + xbar_adx1_out4_ep: endpoint { + remote-endpoint = <&adx1_out4_ep>; + }; + }; + + xbar_adx2_in_port: port@2d { + reg = <0x2d>; + + xbar_adx2_in_ep: endpoint { + remote-endpoint = <&adx2_in_ep>; + }; + }; + + port@2e { + reg = <0x2e>; + + xbar_adx2_out1_ep: endpoint { + remote-endpoint = <&adx2_out1_ep>; + }; + }; + + port@2f { + reg = <0x2f>; + + xbar_adx2_out2_ep: endpoint { + remote-endpoint = <&adx2_out2_ep>; + }; + }; + + port@30 { + reg = <0x30>; + + xbar_adx2_out3_ep: endpoint { + remote-endpoint = <&adx2_out3_ep>; + }; + }; + + port@31 { + reg = <0x31>; + + xbar_adx2_out4_ep: endpoint { + remote-endpoint = <&adx2_out4_ep>; + }; + }; + + xbar_mixer_in1_port: port@32 { + reg = <0x32>; + + xbar_mixer_in1_ep: endpoint { + remote-endpoint = <&mixer_in1_ep>; + }; + }; + + xbar_mixer_in2_port: port@33 { + reg = <0x33>; + + xbar_mixer_in2_ep: endpoint { + remote-endpoint = <&mixer_in2_ep>; + }; + }; + + xbar_mixer_in3_port: port@34 { + reg = <0x34>; + + xbar_mixer_in3_ep: endpoint { + remote-endpoint = <&mixer_in3_ep>; + }; + }; + + xbar_mixer_in4_port: port@35 { + reg = <0x35>; + + xbar_mixer_in4_ep: endpoint { + remote-endpoint = <&mixer_in4_ep>; + }; + }; + + xbar_mixer_in5_port: port@36 { + reg = <0x36>; + + xbar_mixer_in5_ep: endpoint { + remote-endpoint = <&mixer_in5_ep>; + }; + }; + + xbar_mixer_in6_port: port@37 { + reg = <0x37>; + + xbar_mixer_in6_ep: endpoint { + remote-endpoint = <&mixer_in6_ep>; + }; + }; + + xbar_mixer_in7_port: port@38 { + reg = <0x38>; + + xbar_mixer_in7_ep: endpoint { + remote-endpoint = <&mixer_in7_ep>; + }; + }; + + xbar_mixer_in8_port: port@39 { + reg = <0x39>; + + xbar_mixer_in8_ep: endpoint { + remote-endpoint = <&mixer_in8_ep>; + }; + }; + + xbar_mixer_in9_port: port@3a { + reg = <0x3a>; + + xbar_mixer_in9_ep: endpoint { + remote-endpoint = <&mixer_in9_ep>; + }; + }; + + xbar_mixer_in10_port: port@3b { + reg = <0x3b>; + + xbar_mixer_in10_ep: endpoint { + remote-endpoint = <&mixer_in10_ep>; + }; + }; + + port@3c { + reg = <0x3c>; + + xbar_mixer_out1_ep: endpoint { + remote-endpoint = <&mixer_out1_ep>; + }; + }; + + port@3d { + reg = <0x3d>; + + xbar_mixer_out2_ep: endpoint { + remote-endpoint = <&mixer_out2_ep>; + }; + }; + + port@3e { + reg = <0x3e>; + + xbar_mixer_out3_ep: endpoint { + remote-endpoint = <&mixer_out3_ep>; + }; + }; + + port@3f { + reg = <0x3f>; + + xbar_mixer_out4_ep: endpoint { + remote-endpoint = <&mixer_out4_ep>; + }; + }; + + port@40 { + reg = <0x40>; + + xbar_mixer_out5_ep: endpoint { + remote-endpoint = <&mixer_out5_ep>; + }; + }; }; }; }; @@ -1039,6 +1890,31 @@ /* Router */ <&xbar_i2s3_port>, <&xbar_i2s4_port>, <&xbar_dmic1_port>, <&xbar_dmic2_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_mixer_in1_port>, <&xbar_mixer_in2_port>, + <&xbar_mixer_in3_port>, <&xbar_mixer_in4_port>, + <&xbar_mixer_in5_port>, <&xbar_mixer_in6_port>, + <&xbar_mixer_in7_port>, <&xbar_mixer_in8_port>, + <&xbar_mixer_in9_port>, <&xbar_mixer_in10_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&mixer_out1_port>, <&mixer_out2_port>, + <&mixer_out3_port>, <&mixer_out4_port>, + <&mixer_out5_port>, /* I/O DAP Ports */ <&i2s3_port>, <&i2s4_port>, <&dmic1_port>, <&dmic2_port>;
Hi All,
On 8/27/2021 3:03 PM, Sameer Pujar wrote:
Earlier as part of series [0], support for ADMAIF and I/O modules (such as I2S, DMIC and DSPK) was added. This series aims at exposing some of the AHUB internal modules (listed below), which can be used for audio pre or post processing.
- SFC (Sampling Frequency Converter)
- MVC (Master Volume Control)
- AMX (Audio Multiplexer)
- ADX (Audio Demultiplexer)
- Mixer
These modules can be plugged into audio paths and relevant processing can be done. The MUX routes are extended to allow add or remove above modules in the path via mixer controls. This is similar to how specific ADMAIF channels are connected to relevant I/O module instances at the moment.
Some of these modules can alter PCM parameters. Consider example of resampler (44.1 -> 48 kHz) in the path.
aplay(44.1 kHz) -> ADMAIF -> SFC -> (48 kHz) I2S -> (48kHz) Codec
The modules following SFC should be using converted sample rate and DAIs need to be configured accordingly. The audio-graph driver provides a mechanism to fixup the new parameters which can be specified in DT for a given DAI. Then core uses these new values via fixup callback and then pass it to respective DAIs hw_param() callback. The "convert-rate", described in [1], property can be used when there is rate conversion in the audio path. Similarly "convert-channels" can be used when there is channel conversion in the path. There is no "convert-xxx" property for sample size conversions. It can be added if necessary.
In above example, as we see the modules following SFC should be using converted PCM parameters (sample rate in above case). For this I am currently relying on DT properties ('convert-xxx') which is supported by audio-graph-card. This works fine for a static PCM configuration and may be fine to start with. But going ahead a more flexible configuration is preferred (without the need of a reboot). This came up during [0], but now with the introduction of processing modules in the path it becomes more important and would be nice to get this addressed.
Are there any mechanisms in place which can be leveraged to apply PCM configurations at runtime? Or any directions/ideas we want to explore? Any feedback or pointers will be of great help.
[0] https://lkml.org/lkml/2020/2/24/599
Thanks, Sameer.
participants (5)
-
Mark Brown
-
Pierre-Louis Bossart
-
Péter Ujfalusi
-
Rob Herring
-
Sameer Pujar