ALSA

Platform和Codec驱动程序的功能是:

  • tegra210-admaif:代表音频 DMA (ADMA) 和音频集线器 (AHUB) 之间接口的内核驱动程序
  • tegra210-xxxx:代表AHUB中各种硬件加速器的内核驱动
  • tegra210-ahub:一个内核驱动程序,有助于配置各种硬件加速器之间的音频路由

下面一张图是整个AHUB,关于APE架构图由于文档水印显示属于加密,后面我自己画一个再补上
音频处理引擎( APE) 是一个独立的硬件模块,可在 CPU 的最少监督下满足 Jetson 处理器的所有音频需求。其音频集线器 (AHUB) 包含许多硬件加速器和 DMA 引擎。

音频集线器(AHUB)硬件架构

AHUB

音频集线器支持这些设备的不同接口和信号质量要求。ADMAIF生成/dev/snd/pcmC1Dp节点,XBAR上有很多RX/TX,主要用于Codec小组件,比如进行AMX,ADX,SFC,Codec输入均来自XBAR,Codec输出都给XBAR,I2S除外,I2S作为Codec存在,输出端为物理Codec。XBAR上的整个链路的输入输出都通过amixer配置。

  • 每个 AHUB 模块至少具有 1 个 RX 端口或 1 个 TX 端口或两者。

  • RX端口从XBAR接收数据,TX端口向XBAR发送数据。因此,XBAR 是一个开关,根据使用情况,音频输入可以馈送到多个输出。

  • 每个 ADMAIF 都有支持同时播放和捕获的 TX 和 RX FIFO。对于所有音频路由场景,ADMA 将数据传输到 ADMAIF FIFO。

ASoC驱动软件架构

Jetson 的 ASoC 驱动程序的软件架构利用了硬件支持的功能,并符合 ALSA 框架。

如前所述,ASoC 驱动程序由Platform、Codec和Machine驱动程序组成。下面简要描述了这些驱动程序的角色,并在后续部分中更详细地描述了这些驱动程序的角色。

ASoC 驱动程序为Platform和Codec驱动程序提供 NVIDIA 音频中心 (AHUB) 硬件加速。AHUB 直接内存访问接口 (ADMAIF) 被实现为具有用于播放和捕获的 PCM 接口的Platform驱动程序。其余的 AHUB 模块,例如交叉开关 (XBAR)、复用器 (AMX)、解复用器 (ADX) 和 IC 间声音 (I2S),均作为Codec驱动程序实现。每个驱动程序都通过Machine驱动程序内部的数字音频接口(DAI) 连接到 XBAR,形成音频集线器(AHUB)。

Machine驱动程序探针实例化声卡设备并注册 ADMAIF 公开的所有 PCM 接口。启动后,但在使用这些接口进行音频播放或捕获之前,您必须在 XBAR 内设置音频路径。默认情况下,XBAR 在启动时没有路由连接,也没有完整的 DAPM 路径来启动相应的小部件。XBAR 驱动程序为所有音频组件引入了 MUX 小部件,并使用 ALSAamixer实用程序从用户空间通过 kcontrol 实现自定义路由。如果音频路径不完整,则DAPM路径未关闭,硬件设置未应用,并且无法听到音频输出。

Platform驱动程序

ADMAIF

ADMAIF 是 Jetson ASoC 设计中的平台驱动程序。它实现了通过该结构公开的所需 PCM 接口snd_soc_component_driver。这些接口通过与 SoC DMA 引擎的上游 API 交互来帮助执行 DMA 操作。ADMAIF 平台驱动程序定义 DAI 并将其注册到 ASoC 内核。

ADMAIF 通道映射到:

/dev/snd/pcmC1D<n>p用于播放
/dev/snd/pcmC1D<n>c用于捕获

Codec驱动程序

在 ASoC 驱动程序实现中,除 ADMAIF 之外的其余 AHUB 模块均作为Codec驱动程序实现。

XBAR

XBAR Codec驱动程序为所有接口模块定义了 RX、TX 和 MUX 小部件:ADMAIF、AMX、ADX、I2S、DMIC、Mixer、SFC 和 MVC。MUX 小部件永久路由到结构内相应的 TX 小部件snd_soc_dapm_route

XBAR 互连是通过使用 ALSA amixer 实用程序根据需要将任何 RX 小部件块连接到任何 MUX 小部件块来实现的。实现这些小部件的获取和放置处理程序,以便通过在硬件 MUX 寄存器中设置适当的位来存储音频连接。

Mixer Controls

如果开机后声卡可用,则表明Machine驱动程序已成功绑定所有Codec驱动程序和Platform驱动程序。在物理Codec上获取音频输出之前的剩余步骤涉及使用 MUX 小部件来建立 DAPM 路径,以便将数据从特定输入模块路由到特定输出模块。输入和输出模块取决于适用的用例。这为复杂的用例提供了灵活性。

该命令实现内部AHUB路径“ADMAIF1 RX to XBAR to I2S1 TX”:

$ amixer –c APE cset name='I2S1 Mux' 'ADMAIF1'
AMX

音频多路复用器 (AMX) 模块可以将多达 16 个通道(每通道最多 32 位)的四个流复用为最多 16 个通道(每通道最多 32 位)的时分复用 (TDM) 流。AMX 有 4 个 RX 端口用于从 XBAR 接收数据,1 个 TX 端口用于将多路复用输出传输到 XBAR。每个端口都作为 DAI 公开,如下图实线所示。路线是使用 DAPM 小部件建立的,如虚线所示。

AMX 代码驱动程序支持以下功能:

  • 可以多路复用最多 4 个输入流,每个输入流最多 16 个通道,并生成一个最多 16 个通道的输出流,大概就是同时支持4个流的播放。
Mixer Controls

混音器控件由各自的Codec驱动程序为 AMX 的每个实例注册,用于配置音频数据的路径、特性和处理方法。

此示例演示如何使用 AMX 模块复用两个立体声流:DMIC2(连接到 RxCIF0)和 DMIC3(连接到 RxCIF1):

$ amixer -c APE cset name="AMX2 RX1 Mux" "DMIC2"				//解读:AMX2的RX1来自DMIC2
$ amixer -c APE cset name="AMX2 RX2 Mux" "DMIC3"				//解读:AMX2的RX2来自DMIC3
$ amixer -c APE cset name="AMX2 Output Audio Channels" 4		//解读:AMX2的TX为4个通道(每个Mic都是双通道 ?)
$ amixer -c APE cset name="ADMAIF<i> Mux" AMX2					//解读:ADMAIF<i>的RX为AMX2
$ amixer -c APE cset name="ADMAIF<i> Playback Audio Channels" 4
$ amixer -c APE cset name="ADMAIF<i> Capture Audio Channels" 4
$ amixer -c APE cset name="ADMAIF<i> Playback Client Channels" 4
$ amixer -c APE cset name="ADMAIF<i> Capture Client Channels" 4
$ amixer -c APE cset name="AMX2 Byte Map 0" 0
$ amixer -c APE cset name="AMX2 Byte Map 1" 1
$ amixer -c APE cset name="AMX2 Byte Map 2" 2
$ amixer -c APE cset name="AMX2 Byte Map 3" 3
$ amixer -c APE cset name="AMX2 Byte Map 4" 4
$ amixer -c APE cset name="AMX2 Byte Map 5" 5
$ amixer -c APE cset name="AMX2 Byte Map 6" 6
$ amixer -c APE cset name="AMX2 Byte Map 7" 7
$ amixer -c APE cset name="AMX2 Byte Map 8" 64
$ amixer -c APE cset name="AMX2 Byte Map 9" 65
$ amixer -c APE cset name="AMX2 Byte Map 10" 66
$ amixer -c APE cset name="AMX2 Byte Map 11" 67
$ amixer -c APE cset name="AMX2 Byte Map 12" 68
$ amixer -c APE cset name="AMX2 Byte Map 13" 69
$ amixer -c APE cset name="AMX2 Byte Map 14" 70
$ amixer -c APE cset name="AMX2 Byte Map 15" 71
$ arecord -D hw:APE,<i-1> -r 48000 -c 4 -f S16_LE <out_wav>
ADX

音频解复用器 (ADX) 模块可将最多 16 个通道、每通道最多 32 位的单个 TDM 流解复用为最多 16 个通道、每通道 32 位的四个流。ADX 的 RX 端口接收来自 XBAR 的输入数据,四个 TX 端口将解复用的输出传输到 XBAR。每个端口都作为 DAI 公开,由实线表示,并使用 DAPM 小部件建立路由,如下图中的虚线所示。

在这里插入图片描述
ADX 有一个输入 RxCIF,用于提供输入流。核心逻辑根据字节映射从该输入流中选择字节,并形成输出流,这些输出流被定向到 TxCIF FIFO 以传输到 AHUB 中的下游模块。

ADX 解复用器支持以下功能:

  • 将一个最多 16 个通道的输入流解复用为四个最多 16 个通道的输出流
I2S

I2S xxxx驱动程序支持双向数据流,因此定义了 CIF 和 DAP RX/TX DAPM 小部件,其中 I2S 的 CIF 侧与 XBAR 接口,DAP 侧与 Jetson 设备上的物理编解码器接口。

设备树

此 I2S 节点启用给定芯片上的给定 I2S 实例:

aconnect@2a41000 {
	compatible = "nvidia,tegra210-aconnect";
 status = "okay";
	...
	tegra_axbar: ahub {
    	compatible = "nvidia,tegra186-ahub";
    	status = "okay";
    	...
    	tegra_i2s1: i2s@2901000 {
        	compatible = "nvidia,tegra210-i2s";
        	reg = <0x0 0x2901000 0x0 0x100>;
        	clocks = <&bpmp_clks TEGRA194_CLK_I2S1>,
            <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>,
            <&bpmp_clks TEGRA194_CLK_I2S1_SYNC_INPUT>,
            <&bpmp_clks TEGRA194_CLK_SYNC_I2S1>,
            <&bpmp_clks TEGRA194_CLK_I2S1_SYNC_INPUT>;
        	clock-names = "i2s",pll_a_out0, "ext_audio_sync","audio_sync", "clk_sync_input";
        	assigned-clocks = <&bpmp_clks TEGRA194_CLK_I2S1>;
        	assigned-clock-parents =
            <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>;
        	assigned-clock-rates = <1536000>;
        	fsync-width = <31>;
        	#sound-dai-cells = <1>;
        	sound-name-prefix = "I2S1";
        	status = "okay";
    	};
    	...
	};
};
Mixer

Mixer将来自 XBAR 接收数据的 10 个输入端口中任意一个的音频流混合到将数据传输到 XBAR 的 5 个输出端口中的任意一个。Mixer 的 DAPM 小部件和路由如下图所示。Mixer 驱动程序还公开 RX Gain 和 Mixer Enable 作为附加的 kcontrols,以设置每个输入流的音量并分别全局启用或禁用 Mixer。

支持的功能

  • 支持混合多达 10 个输入流
  • 支持 5 个输出,每个输出可以是 10 个输入流的任意组合
SFC

采样频率转换器 (SFC) 将输入采样频率转换为所需的采样率。SFC 有 1 个输入端口和 1 个输出端口,连接到 XBAR。
在这里插入图片描述

支持的功能

  • 最多两个通道的流采样频率转换(立体声)
Mixer Controls for SFC

Mixer 控件由相应的编解码器驱动程序为 SFC 的每个实例注册。它们用于配置音频数据的路径、特性和处理方法。

DMIC(数字Mic)

DMIC 控制器将 PDM 信号转换为 PCM(脉冲编码调制)信号。
在这里插入图片描述

aconnect@2a41000 {
	compatible = "nvidia,tegra210-aconnect";
	status = "okay";
	...
	tegra_axbar: ahub {
    	compatible = "nvidia,tegra186-ahub";
    	status = "okay";
     	. . .
    	tegra_dmic1: dmic@2904000 {
        	compatible = "nvidia,tegra210-dmic";
        	reg = <0x0 0x2904000 0x0 0x100>;
        	clocks = <&bpmp_clks TEGRA194_CLK_DMIC1>,
                 <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>;
       		clock-names = "dmic", "pll_a_out0";
        	assigned-clocks = <&tegra_car TEGRA194_CLK_DMIC1>;
        	assigned-clock-parents =
                    <&tegra_car TEGRA194_CLK_PLLA_OUT0>;
        	assigned-clock-rates = <3072000>;
        	#sound-dai-cells = <1>;
        	sound-name-prefix = "DMIC1";
        	status = "okay";
    	};
        	...
	};
};

ASoC Machine驱动程序

Jetson ASoC 机器驱动程序可在以下位置的内核源存档中找到:

kernel/kernel-5.10/sound/soc/tegra/tegra_machine_driver.c

所有 DAI 链接均在以下位置定义:

hardware/nvidia/platform/tegra/common/kernel-dts/audio/tegra186-audio-dai-links.dtsi

默认情况下,所有 I/O DAI 链路都连接到虚拟端点。这使得 SoC 即使在没有外部设备的情况下也可以驱动接口引脚。它们具有 phandle 引用,可以轻松地用于覆盖特定属性。简而言之,如果您想要连接到特定的外部Codec,则必须覆盖设备树中相应的 DAI 链接。

例如,I2S1 DAI 连接到虚拟Codec,如下所示:

i2s1_to_codec: nvidia-audio-card,dai-link@xxx {
	format = "i2s";
	cpu {
    	sound-dai = <&tegra_i2s1 1>;
	};
	codec {
    	sound-dai = <&tegra_i2s1 2>;
	};
};
定制声卡

以下示例概述了 Jetson AGX Xavier 上板载音频编解码器 (RT5658) 的 DAI 链接和 DAPM 小部件。它使用 SoC I2S1 实例。用户可以类似地根据使用情况和界面为其他 DAI 链接创建覆盖:

hardware/nvidia/platform/t23x/concord/kernel-dts/cvb/tegra234-p3737-audio.dtsi

tegra_sound: sound {
	status = "okay";
	compatible = “nvidia,tegra186-ape”;
	nvidia-audio-card,name = "NVIDIA Jetson AGX Xavier APE";
	clocks = <&bpmp_clks TEGRA194_CLK_PLLA>,
         <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>,
         <&bpmp_clks TEGRA194_CLK_AUD_MCLK>;
	clock-names = "pll_a", "pll_a_out0", "extern1";
	assigned-clocks = <&bpmp_clks TEGRA194_CLK_AUD_MCLK>;
	assigned-clock-parents =
        <&bpmp_clks TEGRA194_CLK_PLLA_OUT0>;
         nvidia-audio-card,widgets =
             "Headphone",    "CVB-RT Headphone Jack",
             "Microphone",   "CVB-RT Mic Jack",
             "Speaker",      "CVB-RT Int Spk",
             "Microphone",   "CVB-RT Int Mic";

         nvidia-audio-card,routing =
             "CVB-RT Headphone Jack",     "CVB-RT HPO L Playback",		//HPO L Playback连接到Headphone Jack输入脚
             "CVB-RT Headphone Jack",		"CVB-RT HPO R Playback",	//HPO R Playback连接到Headphone Jack输入脚
             "CVB-RT IN1P",					"CVB-RT Mic Jack",			//Mic Jack连接到IN1P输入脚
             "CVB-RT IN2P",               "CVB-RT Mic Jack",			//Mic Jack连接到IN2P输入脚
             "CVB-RT Int Spk",            "CVB-RT SPO Playback",		//SPO Playback连接到Int Spk输入脚
             "CVB-RT DMIC L1",            "CVB-RT Int Mic",
             "CVB-RT DMIC L2",            "CVB-RT Int Mic",
             "CVB-RT DMIC R1",            "CVB-RT Int Mic",
             "CVB-RT DMIC R2",            "CVB-RT Int Mic";

	nvidia-audio-card,mclk-fs = <256>;
}
i2c@c250000 {
	rt5658: rt5659.7-001a@1a {
    	compatible = "realtek,rt5658";
    	reg = <0x1a>;
    	...
	};
};

/* Specific overrides for I2S1 DAI link */
&i2s1_to_codec {
	link-name = "rt565x-playback";
	codec {
    	sound-dai = <&rt5658 0>;
    	prefix = "CVB-RT";
	};
};

声音节点被添加到设备树文件中,用于声卡注册并将 Jetson 设备相关数据传递给Machine驱动程序。下面描述了声音节点的一些属性。除另有说明外,所有描述的属性都是必需的。

  • compatible:指定声音节点兼容的Machine驱动程序。它的值一定是nvidia,tegra186-ape.

  • nvidia-audio-card,widgets:定义Machine源或接收器小部件端点。ASoC 内核提供了预定义的标识符,可用于定义所需的小部件。Machine驱动程序不需要显式维护这些小部件,并且可以利用此属性来声明所需的小部件数量。

  • nvidia-audio-card,routing:描述 Jetson ASoC Machine驱动程序小部件和Codec小部件之间的路由。Machine驱动程序为 Jetson 设备的物理麦克风、耳机和扬声器定义 DAPM 小部件。这些必须连接到Codec上相应的 DAPM 小部件,它们代表Codec的麦克风、耳机、扬声器等。

  • link-name:Jetson ASoC Machine驱动程序使用此属性来识别 DAI 链接并执行任何必要的配置,例如Codec时钟设置。

HDA

Jetson 设备通过板载 HDMI、DP 和 USB-C 端口支持一个或多个高清音频 (HDA) 接口。这些接口可用于在电视和 A/V 接收器等设备上执行高质量音频渲染。

HDA 接口可通过标准 ALSA 接口访问。您可以使用该aplay实用程序来渲染音频:

$ aplay -Dhw:HDA,<devID> <wav_in>
  • < deviceID>是声音接口的设备ID。

  • < wav_in>是要播放的声音文件的名称。它应该是一个.wav文件。

USB音频

USB 音频可通过标准 ALSA 接口访问。您可以使用aplay和arecord实用程序分别渲染和捕获音频:

$ aplay -Dhw:<cardID>,<devID> <file_wav>
$ arecord -Dhw:<cardID>,<devID> -r <rate> -c <chan> -f <format> <file_wav>
  • < cardID>是卡 ID,标识声卡类型的字符串: APE或HDA。
  • < devID> 是设备 ID。
  • < file_wav>aplay是输入文件(对于)或输出文件(对于)的名称arecord。它必须是 WAV 文件。
  • < rate>是采样率。
  • < chan>是音频通道的数量。
  • < format>是样本格式

添加自定义声卡

要启用Codec,您必须将Codec添加到用于访问Codec的设备的设备树节点下。大多数Codec使用 I2C 或 SPI 进行访问。在下面的示例中,Codec使用 I2C 作为其控制接口,因此被添加到适当的 I2C 节点:

i2c@<addr> {
	sgtl5000: sgtl5000@0a {
    	compatible = "fsl,sgtl5000";
    	reg = <0x0a>;
    	clocks = <&sgtl5000_mclk>;
    	micbias-resistor-k-ohms = <2>;
    	micbias-voltage-m-volts = <3000>;
    	VDDA-supply = <&vdd_3v3>;
    	VDDIO-supply = <&vdd_3v3>;
    	status = "okay";
	};
};

i2s@<addr> {
	status = "okay";
};

配置 I2S 和Codec DAI 链路

&i2s1_to_codec {
	link-name = "fe-pi-audio-z-v2";
	bitclock-master;	
	frame-master;							//主从配置

	codec {
    	sound-dai = <&sgtl5000>;
    	prefix = “H40-SGTL”;
	};
};
I2S模式设置

要使 I2S 工作在 LRCK 模式 LJM、RJM 或 I2S 下,请将 DAI 链路节点的 format属性分别设置为left_j、right_j或i2s。

要使 I2S 在 TDM 或 FSYNC 模式下运行 ( dsp_a, dsp_b),请将格式属性设置为dsp_a或dsp_b,具体取决于Codec支持的数据偏移量。对于dsp_a或dsp_b模式,帧同步宽度通常是一位时钟。您必须选择dsp-b是要以零时钟位时钟延迟来发送或接收 I2S 数据fsync,还是dsp-a 以一位时钟延迟来发送或接收数据。根据Codec时序图的规范配置 I2S fsync 宽度。以下示例显示了如何操作:

/* I2S DAI link node, override format accordingly */
&i2s<x>_to_codec {
	format = "dsp_a";
};

/* Corresponding I2S device node, set FSYNC width */
i2s@<address> {
	...
	fsync-width = <0>;
};
启用Codec驱动程序
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index e44c2bb..759dfe9 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -204,6 +204,7 @@ config SND_SOC_TEGRA210_AUDIO
    	select SND_SOC_COMPRESS
    	select SND_SOC_RT5640
    	select SND_SOC_RT5659
+       select SND_SOC_SGTL5000
    	help
      		Say Y or M here if you want to enable support for ASoC machine driver on
      		Tegra210 and successor platforms like Tegra186, Tegra194.

p3710代码分析

tegra_virt_ref_alt.c machine
tegra210_virt_alt_admaif.c +256 cpu dai
tegra_asoc_xbar_virt_alt.c +27 codec dai

tegra_asoc_machine_virt_alt.c

SND_SOC_DAILINK_DEFS(audio1,
	DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(1))),
	DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF1 CIF")),
	DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME)));

SND_SOC_DAILINK_DEFS(audio2,
	DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, CPU_DAI_NAME(2))),
	DAILINK_COMP_ARRAY(COMP_CODEC(LINK_CPU_NAME, "ADMAIF2 CIF")),
	DAILINK_COMP_ARRAY(COMP_PLATFORM(PLATFORM_NAME)));

添加A2B驱动

pinmux 配置

调试问题
Drive Orin:
https://forums.developer.nvidia.com/c/autonomous-vehicles/517
Jetson Orin:
https://forums.developer.nvidia.com/tag/audio
https://forums.developer.nvidia.com/t/audio-nosound-card/235566/5
https://forums.developer.nvidia.com/t/agx-orin-with-sgtl5000-has-no-sound/248755

调试命令

zcat /proc/config.gz | grep <config name>
amixer -c APE contents

感谢:

音频设置和开发 — Jetson Linux 开发人员指南 文档
https://blog.csdn.net/wh2526422/article/details/126247382
https://blog.csdn.net/droidphone/article/details/12978287
https://blog.csdn.net/hainei_/article/details/124707205
https://blog.csdn.net/beetleinv/article/details/132061615

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐