Rockchip RK3399 - HDMI音频
目录
----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T4开发板
eMMC :16GB
LPDDR3 :4GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot :2023.04
linux :6.3
----------------------------------------------------------------------------------------------------------------------------
在前面的章节我们已经介绍了machine驱动(simple-audio-card)、platform驱动(i2s)、以及codec驱动(Realtek ALC5651),并测试了通过耳机进行音频的输出。
如果我们想通过HDMI接口进行音频输出的话,我们应该怎么做呢?
我们知道音频驱动主要由三部分组成、machine、platform、codec,这里我们仅仅是更换了codec,将ALC5651更换为了HDMI,其他的并没有什么变化,因此我们只需要进行少量的调整就可以实现通过HDMI进行音频的输出。
一、I2S2接口
我们在Rockchip RK3399 - ALC5651 & I2S基础说过RK3399的I2S2模块,其连接到HDMI和DP的音频接口,支持8通道音频数据传输。
I2S2与HDMI连接(这些引脚没有对外暴露,所以是看不到的):
引脚引脚(I2S2) | 方向 | 功能引脚(HDMI) | 方向 |
I2S2_SCLK_OUT | O | ii2sclk | I |
I2S2_TX_LRCK_OUT | O | ii2slrclk | I |
I2S2_8CH_SDO[3:0] | O | ii2sdata[3:0] | I |
I2S2与DP连接(这些引脚没有对外暴露,所以是看不到的):
引脚引脚(I2S2) | 方向 | 功能引脚(DP) | 方向 |
I2S2_SCLK_OUT | O | source_i2s_clk | I |
I2S2_TX_LRCK_OUT | O | source_i2s_ws | I |
I2S2_8CH_SDO[3:0] | O | source_i2s_data[3:0] | I |
二、设备树配置
2.1 hdmi_sound设备节点
在arch/arm64/boot/dts/rockchip/rk3399.dtsi文件根节点下已经定义了hdmi_sound设备节点:
hdmi_sound: hdmi-sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; simple-audio-card,name = "hdmi-sound"; status = "disabled"; simple-audio-card,cpu { sound-dai = <&i2s2>; }; simple-audio-card,codec { sound-dai = <&hdmi>; }; };
(1) compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;
(2) simple-audio-card,format:指定数字音频接口格式为“I2S”,即使用I2S接口传输音频数据;
此外还支持的数字音频接口格式有:right_j、left_j、dsp_a、dsp_b、ac97、pdm、msb、lsb。
(3) simple-audio-card,mclk-fs:指定主时钟频率MCLK与采样频率之前的比值,例如256表示主时钟频率为系统频率的256倍;
(4) simple-audio-card,name:指定声卡的名称为“hdmi-sound”;
(5) status:指定设备状态为“禁止”,表示该设备状态为禁止运行;
(6) simple-audio-card,cpu:指定cpu接入音频编解码的dai;这里配置为&i2s2,即i2s2设备节点的句柄;
(7) simple-audio-card,codec:指定编解码音频接入cpu的dai;这里配置为&hdmi,即hdmi设备节点的句柄;
我们需要在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件添加如下属性,启用machine驱动:
&hdmi_sound{ status = "okay"; };
2.2 hdmi设备节点
在arch/arm64/boot/dts/rockchip/rk3399.dtsi文件根节点下已经定义了hdmi设备节点:
hdmi: hdmi@ff940000 { compatible = "rockchip,rk3399-dw-hdmi"; reg = <0x0 0xff940000 0x0 0x20000>; interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_SFR>, <&cru SCLK_HDMI_CEC>, <&cru PCLK_VIO_GRF>, <&cru PLL_VPLL>; clock-names = "iahb", "isfr", "cec", "grf", "ref"; power-domains = <&power RK3399_PD_HDCP>; reg-io-width = <4>; rockchip,grf = <&grf>; #sound-dai-cells = <0>; status = "disabled"; ports { hdmi_in: port { #address-cells = <1>; #size-cells = <0>; hdmi_in_vopb: endpoint@0 { reg = <0>; remote-endpoint = <&vopb_out_hdmi>; }; hdmi_in_vopl: endpoint@1 { reg = <1>; remote-endpoint = <&vopl_out_hdmi>; }; }; }; };
关于HDMI设备节点各个属性等我们后面单独介绍。
我们需要在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件添加如下属性,启用hdmi驱动:
&hdmi { ddc-i2c-bus = <&i2c7>; pinctrl-names = "default"; pinctrl-0 = <&hdmi_cec>; status = "okay"; };
2.3 i2s2设备节点
在arch/arm64/boot/dts/rockchip/rk3399.dtsi文件根节点下已经定义了i2s2设备节点:
i2s2: i2s@ff8a0000 { compatible = "rockchip,rk3399-i2s", "rockchip,rk3066-i2s"; reg = <0x0 0xff8a0000 0x0 0x1000>; interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH 0>; dmas = <&dmac_bus 4>, <&dmac_bus 5>; dma-names = "tx", "rx"; clock-names = "i2s_clk", "i2s_hclk"; clocks = <&cru SCLK_I2S2_8CH>, <&cru HCLK_I2S2_8CH>; power-domains = <&power RK3399_PD_SDIOAUDIO>; #sound-dai-cells = <0>; status = "disabled"; };
这是Rockchip RK3399中I2S2设备节点描述。它包括以下属性:
- compatible:指定设备驱动程序的兼容性,即告诉内核该设备可以被哪些驱动程序所使用;
- reg:指定I2S0控制器的基地址和地址空间大小,从0xff8a0000到0xff8a1000共有0x1000个字节的寄存器空间,其中0xff8a0000为I2S2寄存器基地址;
- interrupts:指定I2S控制器的中断号为GIC_SPI 41,并且取值方式为IRQ_TYPE_LEVEL_HIGH,意味着中断信号为高电平触发;
- dmas:指定数据传输时使用的DMA控制器,第一个表示tx数据使用的DMA控制器,第二个表示rx数据使用的DMA控制器;
- dma-names:分别对应"tx"和"rx"的DMA名称;
- clock-names:指定时钟名称,"i2s_clk"表示I2S0控制器时钟,"i2s_hclk" 表示I2S总线时钟;
- clocks:i2s_clk时钟来自SCLK_I2S2_8CH,i2s_hclk时钟来自HCLK_I2S2_8CH;
- power-domains:指定设备隶属于的电源域,这里是 RK3399_PD_SDIOAUDIO;
- #sound-dai-cells:表示定义这个节点的sound DAI数据单元格的数量,这里为0表示没有单元格;
- status:表示设备状态,这里 "disabled" 表示该设备当前是禁用状态;
我们需要在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件添加如下属性,启用platform驱动:
&i2s2 { status = "okay"; };
三、内核配置
3.1 内核配置
3.1.1 HDMI配置
在linux内核根目录下执行make menuconfig配置以下选项:
Device Drivers ---> Graphics support ---> [*] Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) ---> [*] DRM Support for Rockchip Display Interface Bridges ---> [*] Synopsys Designware I2S Audio interface # 对应DRM_DW_HDMI_I2S_AUDIO
确保编译配置里有HDMI相关配置,如果缺少了自己补上:
CONFIG_DRM=y #必须 CONFIG_DRM_ROCKCHIP=y #必须 CONFIG_ROCKCHIP_DW_HDMI=y #必须 CONFIG_ROCKCHIP_INNO_HDMI=y CONFIG_DRM_PANEL_SIMPLE=y #必须 CONFIG_DRM_DW_HDMI_I2S_AUDIO=y #必须 CONFIG_DRM_DW_HDMI_CEC=y
3.1.2 其他
关于I2S、以及simple-audio-card驱动的配置,我们在Rockchip RK3399 - ALC5651音频调试其实已经介绍过了:
Device Drivers ---> <*> Sound card support ---> <*> Advanced Linux Sound Architecture --->
<*> Sequencer support <*> ALSA for SoC audio support ---> <*> ASoC support for Rockchip {*} Rockchip I2S Device Driver <*> ASoC Simple sound card support
确保编译配置里有如下相关配置,如果缺少了自己补上:
CONFIG_SND_SEQUENCER=y CONFIG_SND_SEQ_DUMMY=y CONFIG_SND_HRTIMER=y CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_SOC=y CONFIG_SND_SOC_ROCKCHIP=y CONFIG_SND_SOC_ROCKCHIP_I2S=y CONFIG_SND_SIMPLE_CARD=y
配置完内核之后记得保存配置,存档:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# mv rk3399_defconfig ./arch/arm64/configs/
重新配置内核:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make rk3399_defconfig
3.2 编译内核
在linux内核根目录下执行如下命令进行编译内核:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make -j8
u-boot-2023.04路径下的mkimage工具拷贝过来,然后在命令行使用mkimage工具编译即可:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp ../u-boot-2023.04/tools/mkimage ./ root@zhengyang:/work/sambashare/rk3399/linux-6.3# ./mkimage -f kernel.its kernel.itb
3.3 通过tftp烧录内核
给开发板上电,同时连接上网线,进入uboot命令行。我们将内核拷贝到tftp文件目录:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp kernel.itb /work/tftpboot/
接着给开发板上电。通过uboot命令行将kernel.itb下到内存地址0x10000000处:
=> tftp 0x10000000 kernel.itb
通过mmc write命令将内核镜像烧录到eMMC第0x8000个扇区处:
=> mmc erase 0x8000 0xA000 => mmc write 0x10000000 0x8000 0xA000
四、测试
4.1 查看音频设备节点
查看音频设备节点:
root@rk3399:/# ll /dev/snd drwxr-xr-x 2 root root 80 Aug 6 15:04 by-path/ crw-rw---- 1 root audio 116, 4 Aug 6 15:04 controlC0 crw-rw---- 1 root audio 116, 7 Aug 6 15:04 controlC1 crw-rw---- 1 root audio 116, 3 Aug 6 15:04 pcmC0D0c crw-rw---- 1 root audio 116, 2 Aug 6 15:04 pcmC0D0p crw-rw---- 1 root audio 116, 6 Aug 6 15:04 pcmC1D0c crw-rw---- 1 root audio 116, 5 Aug 6 15:04 pcmC1D0p crw-rw---- 1 root audio 116, 1 Aug 6 15:04 seq crw-rw---- 1 root audio 116, 33 Aug 6 15:04 timer
其中:
- controlCx:用于声卡的控制,例如通道选择,混音,麦克控制,音量加减,开关等;
- pcmCxD0c:用于录音的pcm设备;
- pcmCxD0p:用于播放的pcm设备;
- seq:音序器;
- timer:定时器;
C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。
从上面的列表可以看出,我里应该是有2个声卡,声卡0/1下各挂了3个设备,根据声卡的实际能力,驱动实际上可以挂载更多种类的设备,我们通常更关心的是pcm和control这两种设备,默认一个声卡对应一个Control设备。
4.2 查看所有声卡
查看所有声卡:
root@rk3399:/# cat /proc/asound/cards 0 [hdmisound ]: simple-card - hdmi-sound hdmi-sound 1 [realtekrt5651co]: simple-card - realtek,rt5651-codec realtek,rt5651-codec
第一个数字为声卡编号,第二个数字为声卡唯一标识,最长16个字符。以声卡编号1为例:
1为声卡编号,realtekrt5651co为ALSA声卡的唯一标识,因为struct snd_card id字段其长度为16,所以存放的就是realtek,rt5651-codec去除特殊字符之后的的前15个字符。
声卡分两种通道,一种是Capture、一种是Playback。Capture是输入通道,Playback是输出通道;我们以声卡0为例;
root@rk3399:/# ll /proc/asound/card0 -r--r--r-- 1 root root 0 Aug 6 16:43 id dr-xr-xr-x 5 root root 0 Aug 6 16:43 pcm0c/ dr-xr-xr-x 5 root root 0 Aug 6 16:43 pcm0p/ root@rk3399:/# cat /proc/asound/card0/id hdmisound
pcm0p属于声卡0输出通道,pcm0c属于声卡0输入通道。
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了