rk3588/kernel-6.1 sound 声卡架构分析
本文面向 rk3588/kernel-6.1/sound,重点分析 ALSA/ASoC 在内核中的分层、对象模型、主数据路径与 Rockchip 适配方式,帮助你把“声卡驱动代码”放进整体内核架构里理解。
1. sound 子系统总体分层
从 sound/Makefile 与 sound/Kconfig 可以看到该目录有三层语义:
通用声卡核心层(ALSA Core)
- 入口配置:
CONFIG_SND
- 关键目录:
sound/core/
- 提供
snd_card、control(混音器/控制)、PCM、timer、rawmidi 等统一抽象。
SoC 音频框架层(ASoC)
- 入口配置:
CONFIG_SND_SOC
- 关键目录:
sound/soc/
- 将 SoC 音频拆成 CPU DAI、Codec、Platform/Machine 三类组件,用
snd_soc_card + snd_soc_dai_link 进行装配。
平台/总线具体实现层
- 目录:
sound/soc/rockchip/、sound/usb/、sound/hda/、sound/pci/ 等
- 这里放控制器驱动、编解码器绑定、板级 machine driver。
对 RK3588 而言,主路径通常是:
ASoC Core (sound/soc) + Rockchip CPU DAI 控制器 (sound/soc/rockchip/*) + 外部/内部 Codec + 板级 machine card。
2. ALSA Core 关键对象与生命周期
2.1 声卡对象 snd_card
在 sound/core/init.c 中,典型生命周期是:
snd_card_new():分配并初始化声卡对象(含控制链表、文件跟踪、sysfs 设备等)
- 驱动创建并挂接各子设备(control/pcm/…)
snd_card_register():把 card 及其子设备真正注册给用户空间可见
- 热插拔/卸载:
snd_card_disconnect() / snd_card_free()
这说明 snd_card 是 ALSA 的“根设备容器”,其下挂所有控制与数据平面对象。
2.2 控制面(Mixer/Control)
sound/core/control.c 中核心是 snd_kcontrol:
- 创建控制项:
snd_ctl_new1()
- 加入声卡:
snd_ctl_add()
- 用户态通过
SNDRV_CTL_IOCTL_* 读写控制值
- 变化通知:
snd_ctl_notify()、snd_ctl_notify_one()
因此控制面是“状态配置 + 事件通知”通道,不直接搬运音频样本数据。
2.3 数据面(PCM)
sound/core/pcm.c 中核心是 snd_pcm / snd_pcm_substream / snd_pcm_runtime:
- 创建设备:
snd_pcm_new()
- 设置流操作:
snd_pcm_set_ops()
- 注册字符设备:
snd_pcm_dev_register(),映射到 /dev/snd/pcmC*D*[pc]
- 运行时通过
open/hw_params/prepare/trigger/pointer 协议驱动 DMA/中断传输
3. ASoC 架构:把 SoC 音频“组装成卡”
sound/soc/soc-core.c 是 ASoC 主轴。核心对象关系:
snd_soc_component:可复用组件(CPU DAI 控制器、Codec、平台组件)
snd_soc_dai:具体数字音频接口端点
snd_soc_dai_link:描述 CPU DAI 与 Codec DAI 的连线关系
snd_soc_pcm_runtime (rtd):每条 link 的运行时对象
snd_soc_card:整卡聚合对象,最终绑定到 snd_card
3.1 绑定流程(核心调用链)
机器驱动调用 snd_soc_register_card() 后,进入:
snd_soc_bind_card()
snd_soc_add_pcm_runtime()(为每条 dai_link 创建 rtd)
snd_card_new()(创建 ALSA card)
soc_probe_link_components() / soc_probe_link_dais()
soc_init_pcm_runtime() -> soc_new_pcm()(创建 PCM 设备)
snd_soc_dapm_*(构建音频电源图与路由)
snd_card_register()(向用户空间发布声卡)
这条链路把“设备树 + 驱动组件”最终落地成 /proc/asound、/dev/snd/* 可见设备。
3.2 DAPM 的作用
ASoC 不只关心数据传输,还通过 DAPM(Dynamic Audio Power Management)管理模拟/数字路径电源域,减少功耗并抑制 Pop/Click。
soc-core.c 里可看到 snd_soc_dapm_add_routes()、snd_soc_dapm_sync()、snd_soc_dapm_stream_event() 等关键流程。
4. Rockchip 声卡架构落点(sound/soc/rockchip)
sound/soc/rockchip/Kconfig + Makefile 显示 Rockchip 体系可分为两类:
控制器/DAI 驱动(CPU DAI)
例如 rockchip_i2s_tdm.c、rockchip_i2s.c、rockchip_pdm*.c、rockchip_spdif*.c、rockchip_sai.c。
Machine/Card 驱动(板级装配)
例如 rockchip_hdmi.c、rockchip_rt5645.c、rockchip_multicodecs.c 等,负责拼接 cpu/codec/platform 并注册 snd_soc_card。
RK3588 常见核心在 rockchip_i2s_tdm.c(控制器)与具体 machine 驱动组合。
5. 典型驱动解剖
5.1 CPU DAI:rockchip_i2s_tdm.c
这是 Rockchip I2S/TDM 控制器主驱动,关键点:
- DAI ops:
rockchip_i2s_tdm_dai_ops
实现 startup/shutdown/hw_params/hw_free/trigger/set_fmt/set_sysclk/set_tdm_slot。
- 组件注册:
devm_snd_soc_register_component(..., &rockchip_i2s_tdm_component, i2s_tdm->dai, 1)
把 component + dai 暴露给 ASoC core。
- 平台 PCM 对接:
rockchip_i2s_tdm_register_platform()
按场景注册 snd_dmaengine_pcm、TRCM 或 DLP。
- 中断与 XRUN:
rockchip_i2s_tdm_isr()
处理 TX underrun / RX overrun,并调用 snd_pcm_stop_xrun()。
- PM 运行时电源:
i2s_tdm_runtime_suspend() / i2s_tdm_runtime_resume()
维护时钟、regcache、pinctrl、DMA 状态。
说明该文件同时承担:寄存器控制 + DMA 数据平面 + ASoC DAI 接口 + PM。
5.2 Machine Driver:rockchip_hdmi.c
rk_hdmi_probe() 做的事很典型:
- 从 DT 解析 card 名称、CPU/Codec 节点、
dai_fmt、mclk-fs
- 组装
snd_soc_dai_link(cpus/codecs/platforms)
- 设置
ops(如 rk_hdmi_hw_params,配置 CPU/Codec sysclk)
devm_snd_soc_register_card() 注册整卡
其中 rk_dailink_init() 还创建 HDMI jack 与 DAPM widget,体现 machine driver 对“板级音频拓扑”的职责。
6. 从用户态到硬件的数据路径
以播放为例,主链路可抽象为:
- 用户态
alsa-lib/tinyalsa 打开 pcmC*D*p
sound/core/pcm.c 分配 snd_pcm_substream/runtime
hw_params 下发到 ASoC runtime
- ASoC 调到 CPU DAI
rockchip_i2s_tdm_hw_params()
- 配置格式/通道/时钟/slot/DMA 参数
trigger(START) -> 使能 DMA 与 I2S/TDM XFER
- 中断/DMA 推进,
pointer 上报 hw_ptr
- 异常时 IRQ 触发 XRUN 处理
控制面(音量、开关、路由)并行走 control.c 的 snd_kcontrol 机制,不与 PCM 样本搬运混淆。
7. RK3588 视角下的配置与裁剪建议
最小可用链路
CONFIG_SND + CONFIG_SND_SOC + CONFIG_SND_SOC_ROCKCHIP + 对应接口(如 SND_SOC_ROCKCHIP_I2S_TDM)+ 目标 codec/machine 配置。
按硬件接口启用
仅启用实际使用的 I2S/TDM/PDM/SPDIF/SAI,减少镜像体积和 probe 噪音。
DT 与驱动一致性
sound-dai、rockchip,cpu、rockchip,codec、路由与时钟属性必须与 machine/cpu dai 预期一致,否则常见 -EPROBE_DEFER 或注册失败。
8. 调试抓手(实战)
设备枚举
/proc/asound/cards
/proc/asound/pcm
ASoC 拓扑与 DAPM
- debugfs:
/sys/kernel/debug/asoc/
- 检查 dai 列表、component 列表、路由与电源状态
关键日志定位
snd_soc_register_card failed
CODEC DAI ... not registered(通常是 probe 顺序或 DT 绑定问题)
TX FIFO Underrun / RX FIFO Overrun(带宽、时钟、DMA阈值、buffer 参数问题)
优先核对四件事
dai_fmt(I2S/LJ/RJ、主从、极性)
mclk/bclk/lrck 比例
- DMA burst/period/buffer
- DAPM route 与 pin switch
9. 结论
sound 子系统在 RK3588 内核中本质是“ALSA Core + ASoC 装配框架 + Rockchip CPU DAI/Machine 实现”的三层协作:
- ALSA Core 提供统一用户态 ABI 与控制/PCM 抽象;
- ASoC 负责组件发现、link 绑定、DAPM 电源与运行时 orchestration;
- Rockchip 驱动将 I2S/TDM 等硬件细节映射为标准 DAI/PCM 操作。
理解 snd_card -> snd_soc_card -> dai_link/rtd -> cpu_dai_ops 这条主线后,定位声卡问题会明显更快:先判断是“卡没起来(绑定问题)”还是“流不通(时钟/格式/DMA问题)”。