rk3588/kernel-6.1 sound 声卡架构分析

rk3588/kernel-6.1 sound 声卡架构分析

本文面向 rk3588/kernel-6.1/sound,重点分析 ALSA/ASoC 在内核中的分层、对象模型、主数据路径与 Rockchip 适配方式,帮助你把“声卡驱动代码”放进整体内核架构里理解。


1. sound 子系统总体分层

sound/Makefilesound/Kconfig 可以看到该目录有三层语义:

  1. 通用声卡核心层(ALSA Core)

    • 入口配置:CONFIG_SND
    • 关键目录:sound/core/
    • 提供 snd_card、control(混音器/控制)、PCM、timer、rawmidi 等统一抽象。
  2. SoC 音频框架层(ASoC)

    • 入口配置:CONFIG_SND_SOC
    • 关键目录:sound/soc/
    • 将 SoC 音频拆成 CPU DAI、Codec、Platform/Machine 三类组件,用 snd_soc_card + snd_soc_dai_link 进行装配。
  3. 平台/总线具体实现层

    • 目录: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() 后,进入:

  1. snd_soc_bind_card()
  2. snd_soc_add_pcm_runtime()(为每条 dai_link 创建 rtd
  3. snd_card_new()(创建 ALSA card)
  4. soc_probe_link_components() / soc_probe_link_dais()
  5. soc_init_pcm_runtime() -> soc_new_pcm()(创建 PCM 设备)
  6. snd_soc_dapm_*(构建音频电源图与路由)
  7. 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 体系可分为两类:

  1. 控制器/DAI 驱动(CPU DAI)
    例如 rockchip_i2s_tdm.crockchip_i2s.crockchip_pdm*.crockchip_spdif*.crockchip_sai.c

  2. Machine/Card 驱动(板级装配)
    例如 rockchip_hdmi.crockchip_rt5645.crockchip_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 opsrockchip_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。
  • 中断与 XRUNrockchip_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_fmtmclk-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. 从用户态到硬件的数据路径

以播放为例,主链路可抽象为:

  1. 用户态 alsa-lib/tinyalsa 打开 pcmC*D*p
  2. sound/core/pcm.c 分配 snd_pcm_substream/runtime
  3. hw_params 下发到 ASoC runtime
  4. ASoC 调到 CPU DAI rockchip_i2s_tdm_hw_params()
  5. 配置格式/通道/时钟/slot/DMA 参数
  6. trigger(START) -> 使能 DMA 与 I2S/TDM XFER
  7. 中断/DMA 推进,pointer 上报 hw_ptr
  8. 异常时 IRQ 触发 XRUN 处理

控制面(音量、开关、路由)并行走 control.csnd_kcontrol 机制,不与 PCM 样本搬运混淆。


7. RK3588 视角下的配置与裁剪建议

  1. 最小可用链路
    CONFIG_SND + CONFIG_SND_SOC + CONFIG_SND_SOC_ROCKCHIP + 对应接口(如 SND_SOC_ROCKCHIP_I2S_TDM)+ 目标 codec/machine 配置。

  2. 按硬件接口启用
    仅启用实际使用的 I2S/TDM/PDM/SPDIF/SAI,减少镜像体积和 probe 噪音。

  3. DT 与驱动一致性
    sound-dairockchip,cpurockchip,codec、路由与时钟属性必须与 machine/cpu dai 预期一致,否则常见 -EPROBE_DEFER 或注册失败。


8. 调试抓手(实战)

  1. 设备枚举

    • /proc/asound/cards
    • /proc/asound/pcm
  2. ASoC 拓扑与 DAPM

    • debugfs: /sys/kernel/debug/asoc/
    • 检查 dai 列表、component 列表、路由与电源状态
  3. 关键日志定位

    • snd_soc_register_card failed
    • CODEC DAI ... not registered(通常是 probe 顺序或 DT 绑定问题)
    • TX FIFO Underrun / RX FIFO Overrun(带宽、时钟、DMA阈值、buffer 参数问题)
  4. 优先核对四件事

    • 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问题)”。

文章互动

阅读 --

留言

0 条留言

正在加载留言…