瑞芯微Rockchip开发者社区
直播中

吴凡

10年用户 924经验值
擅长:48674
私信 关注
[问答]

如何去实现RK3288 HDMIin音频通路的设计呢

如何去 HDMI 实现监听 RK3288 的设计呢?

回帖(2)

陈瑞微

2022-3-4 09:14:53
1
举报

h1654155275.5916

2022-3-4 09:15:03
  这里先说下rk3288 HDMIin音频通路:
  hdmiin:
  HDMIIn声音直接通过codec输出到喇叭、耳机,不需要送到主控进行处理:
  TC358749XBG-》 alc5651 i2s2 -》 alc5651 dac -》 hp/lineout
  
  alsa HAL 层
  RK平台 android 5.1 BOX MID的SDK之后统一使用这个目录下面的代码
  hardwarerockchipaudiotinyalsa_hal
  嵌入式设备的音频系统可以被划分为板载硬件(Machine)、Soc(Platform)、Codec 三大部分
  1、音频编解码器 Codec 负责处理音频信息,包括 ADC,DAC,Mixer,DSP,输入输出以及音量控制等所有
  与音频相关的功能。
  Codec 与处理器之间通过 I2C 总线和数字音频接口 DAI 进行通信。
  I2C 总线 - 实现对 Codec 寄存器数据的读写。
  2、DAI –(digital audio interface)实现音频数据在 CPU 和 Codec 间的通信,包括 I2S、PCM 和 AC97
  等。
  蓝牙立体声音乐播放走的是蓝牙跟 CPU 直接的 UART 接口。
  在只有一组 I2S 的主控上面,蓝牙通话 SCO 暂时是通过 Codec 中继,即通过 codec 来路由选择是
  否走通话,走的是 I2S 接口 。如果主控有两组 I2S,那么可以将 BT PCM 直接接到主控的 PCM 接
  口上。
  S/DIF(Sony/Philips Digital Interface Format),通过光纤或同轴电缆传输音频,保证音频质量。
  Codec 内部通路举例 RK616
  同时音频驱动有三部分:
  Machine driver
  sound/soc/rockchip/rk_rk616.c
  其中的 Machine 驱动负责 Platform 和 Codec 之间的耦合以及部分和设备或板子特定的代码采样率
  时钟配置
  Platform driver
  sound/soc/ rockchip /rk30_i2s.c
  I2S 控制器驱动 采样率时钟 DMA 等配置
  Codec driver
  sound/soc/codecs/rk616_codec.c
  codec 的寄存器通路的配置
  android audio route通路介绍
  android定义了很多的音频devices:在frameworks/base/media/java/android/media/AudioSystem.java文件中
  349 // output devices, be sure to update AudioManager.java also
  350 public static final int DEVICE_OUT_EARPIECE = 0x1;
  351 public static final int DEVICE_OUT_SPEAKER = 0x2;
  352 public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
  353 public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
  354 public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
  355 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
  356 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
  357 public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
  358 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
  359 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
  360 public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
  361 public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL;
  362 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
  363 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
  364 public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
  365 public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
  366 public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
  367 public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000;
  368 public static final int DEVICE_OUT_LINE = 0x20000;
  369 public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
  370 public static final int DEVICE_OUT_SPDIF = 0x80000;
  371 public static final int DEVICE_OUT_FM = 0x100000;
  372 public static final int DEVICE_OUT_AUX_LINE = 0x200000;
  373 public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
  374 public static final int DEVICE_OUT_IP = 0x800000;
  375 public static final int DEVICE_OUT_BUS = 0x1000000;
  HAL层通过一定转换跟android上层对应
  在hardware/rockchip/audio/tinyalsa_hal/alsa_route.c 中通过route_set_controls(route)中通过 get_route_config(int route)将以上的各个route值转换为codec_config中的xxx.h配置文件。
  文件:。/hardware/rockchip/audio/tinyalsa_hal/alsa_route.c
  282 const struct config_route *get_route_config(unsigned route) //即在这里获取音频路由设备
  283 {
  284 ALOGV(“get_route_config() route %d”, route);
  285
  286
  287 if (!route_table) {
  288 ALOGE(“get_route_config() route_table is NULL!”);
  289 return NULL;
  290 }
  291 switch (route) {
  292 case SPEAKER_NORMAL_ROUTE:
  293 return &(route_table-》speaker_normal);
  。..。..
  HAL层中定义的 route table,再通过route_set_controls将这些table配置,最终设置到codec的寄存器
  文件:。/hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
  1110 const struct config_route_table rt5651_config_table = {
  1111 //speaker
  1112 .speaker_normal = {
  1113 .sound_card = 0,
  1114 .devices = DEVICES_0,
  1115 .controls = rt5651_speaker_normal_controls,
  1116 .controls_count = sizeof(rt5651_speaker_normal_controls) / sizeof(struct config_control),
  1117 },
  。..。..
  48 const struct config_control rt5651_speaker_normal_controls[] = {
  56
  57 {
  58 .ctl_name = “DAC MIXL INF1 Switch”,
  59 .int_val = {on},
  60 },
  61 {
  62 .ctl_name = “DAC MIXR INF1 Switch”,
  63 .int_val = {on},
  64 },
  65 {
  66 .ctl_name = “Stereo DAC MIXL DAC L1 Switch”,
  67 .int_val = {on},
  68 },
  69 {
  70 .ctl_name = “Stereo DAC MIXR DAC R1 Switch”,
  71 .int_val = {on},
  72 },
  73 {
  74 .ctl_name = “OUT MIXL DAC L1 Switch”,
  75 .int_val = {on},
  76 },
  77 {
  78 .ctl_name = “OUT MIXR DAC R1 Switch”,
  79 .int_val = {on},
  80 },
  81
  HAL层会根据sound card name选择使用哪个table,如果没有匹配默认使用default_config.h
  文件:。/hardware/rockchip/audio/tinyalsa_hal/alsa_route.c
  89 /**
  90 * @brief route_init
  91 *
  92 * @returns
  93 */
  94 int route_init(void)
  95 {
  96 char soundCardID[20] = “”;
  97 static FILE * fp;
  98 unsigned i, config_count = sizeof(sound_card_config_list) / sizeof(struct alsa_sound_card_config);
  99 size_t read_size;
  100
  101 ALOGV(“route_init()”);
  102
  103 fp = fopen(“/proc/asound/card0/id”, “rt”); //id是第0个声卡,串口执行cat /proc/asound/card0/id可以查看
  104 if (!fp) {
  105 ALOGE(“Open sound card0 id error!”);
  106 } else {
  107 read_size = fread(soundCardID, sizeof(char), sizeof(soundCardID), fp);
  108 fclose(fp);
  109
  110 if (soundCardID[read_size - 1] == ‘n’) {
  111 read_size--;
  112 soundCardID[read_size] = ‘’;
  113 }
  114
  115 ALOGV(“Sound card0 is %s”, soundCardID);
  116
  117 for (i = 0; i 《 config_count; i++) {
  118 if (!(sound_card_config_list + i) || !sound_card_config_list[i].sound_card_name ||
  119 !sound_card_config_list[i].route_table)
  120 continue;
  121
  122 if (strncmp(sound_card_config_list[i].sound_card_name, soundCardID, //根据sound card name选择使用哪个table
  123 read_size) == 0) {
  124 route_table = sound_card_config_list[i].route_table;
  125 ALOGD(“Get route table for sound card0 %s”, soundCardID);
  126 }
  127 }
  128 }
  129
  130 if (!route_table) {
  131 route_table = &default_config_table; //如果没有匹配默认使用default_config.h
  132 ALOGD(“Can not get config table for sound card0 %s, so get default config table.”, soundCardID);
  133 }
  134
  135 for (i = PCM_DEVICE0_PLAYBACK; i 《 PCM_MAX; i++)
  136 mPcm[i] = NULL;
  137
  138 return 0;
  139 }
  HAL层声卡名称sound card name和配置表列表table的声明在 。/tinyalsa_hal/codec_config/config_list.h 文件中。Audio将获取config_route_table并根据声卡0(识别到的声卡列表的第一个)和sound_card_name的名称设置路由route。
  rk3288:/ # cat /proc/asound/card0/id
  realtekrt5651co
  文件:。/hardware/rockchip/audio/tinyalsa_hal/codec_config/config_list.h
  71 struct alsa_sound_card_config sound_card_config_list[] = {
  72 {
  73 .sound_card_name = “RKRK616”,
  74 .route_table = &rk616_config_table,
  75 },
  76 {
  77 .sound_card_name = “RK29RT3224”,
  78 .route_table = &rt3224_config_table,
  79 },
  80 {
  81 .sound_card_name = “rockchiprt5640c”,
  82 .route_table = &rt5640_config_table,
  83 },
  84 {
  85 .sound_card_name = “rockchipes8396c”,
  86 .route_table = &es8396_config_table,
  87 },
  88 {
  89 .sound_card_name = “RK29RT3261”,
  90 .route_table = &rt3261_config_table,
  91 },
  92 {
  93 .sound_card_name = “RK29WM8960”,
  94 .route_table = &wm8960_config_table,
  95 },
  96 {
  97 .sound_card_name = “RKRT3224”,
  98 .route_table = &rt3224_config_table,
  99 },
  100 {
  101 .sound_card_name = “RKRT3261”,
  102 .route_table = &rt3261_config_table,
  103 },
  104 {
  105 .sound_card_name = “RKWM8960”,
  106 .route_table = &wm8960_config_table,
  107 },
  108 {
  109 .sound_card_name = “RKRT5616”,
  110 .route_table = &rt5616_config_table,
  111 },
  112 {
  113 .sound_card_name = “realtekrt5651co”,
  114 .route_table = &rt5651_config_table,
  115 },
  。..。..
  .route_table的引用对应在xxxx_config.h文件中有定义,例如.route_table = &rt5651_config_table在rt5651_config.h中。
  文件:/hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
  1143 const struct config_route_table rt5651_config_table = {
  1144 //speaker
  1145 .speaker_normal = {
  1146 .sound_card = 0,
  1147 .devices = DEVICES_0,
  1148 .controls = rt5651_speaker_normal_controls,
  1149 .controls_count = sizeof(rt5651_speaker_normal_controls) / sizeof(struct config_control),
  1150 },
  1151 .speaker_incall = {
  1152 .sound_card = 0,
  1153 .devices = DEVICES_0,
  1154 .controls = rt5651_speaker_incall_controls,
  1155 .controls_count = sizeof(rt5651_speaker_incall_controls) / sizeof(struct config_control),
  1156 },
  。..。..
  然后再在.controls当中配置ctl_name和int_val,例如rt5651_speaker_normal_controls的配置,对应在kernel层会获取到这里的设置。
  const struct config_control rt5651_speaker_normal_controls[] = {
  99 {
  100 .ctl_name = “RT5651 ASRC Switch”,
  101 .int_val = {1},
  102 },
  103
  104 {
  105 .ctl_name = “DAC MIXL INF1 Switch”,
  106 .int_val = {on},
  107 },
  108 {
  109 .ctl_name = “DAC MIXR INF1 Switch”,
  110 .int_val = {on},
  111 },
  112 {
  113 .ctl_name = “Stereo DAC MIXL DAC L1 Switch”,
  114 .int_val = {on},
  115 },
  116 {
  117 .ctl_name = “Stereo DAC MIXR DAC R1 Switch”,
  118 .int_val = {on},
  119 },
  120 {
  121 .ctl_name = “OUT MIXL DAC L1 Switch”,
  122 .int_val = {on},
  123 },
  124 {
  125 .ctl_name = “OUT MIXR DAC R1 Switch”,
  126 .int_val = {on},
  127 },
  128 {
  129 .ctl_name = “HPOVOL L Switch”,
  130 .int_val = {on},
  131 },
  132 {
  133 .ctl_name = “HPOVOL R Switch”,
  134 .int_val = {on},
  135 },
  136 {
  137 .ctl_name = “HPO MIX HPVOL Switch”,
  138 .int_val = {on},
  139 },
  140 {
  141 .ctl_name = “HPO MIX HPVOL Switch”,
  142 .int_val = {on},
  143 },
  144 {
  145 .ctl_name = “HPO L Playback Switch”,
  146 .int_val = {on},
  147 },
  148 {
  149 .ctl_name = “HPO R Playback Switch”,
  150 .int_val = {on},
  151 },
  156 { .ctl_name = “LOUT MIX DAC L1 Switch”, .int_val = {on}, },
  157 { .ctl_name = “LOUT MIX DAC R1 Switch”, .int_val = {on}, },
  158
  159 // SPEAKER_NORMAL_ROUTE HEADSET_NORMAL_ROUTE
  160 { .ctl_name = “LOUT MIX OUTVOL L Switch”, .int_val = {on}, },
  161 { .ctl_name = “LOUT MIX OUTVOL R Switch”, .int_val = {on}, },
  162
  163 { .ctl_name = “LOUT L Playback Switch”, .int_val = {on}, },
  164 { .ctl_name = “LOUT R Playback Switch”, .int_val = {on}, },
  165
  166 //{ .ctl_name = “OUT Playback Volume”, .int_val = {26, 26}, }, // 31 31
  167
  168 { .ctl_name = “DAC1 Playback Volume”, .int_val = {128, 128}, }, // {136, 136} //这里是音量设置
  };
  音量值调节:
  hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
  const struct config_control rt5651_bluetooth_voip_controls[] = {
  // init IN2p/n for line in input.
  const struct config_control rt5651_line_in_capture_controls[] = {
  // try run it first, to fix conflict
  { .ctl_name = “RECMIXL INL1 Switch”, .int_val = {on}, }, //Replace mic: conf for L.in.L used
  { .ctl_name = “RECMIXR INR1 Switch”, .int_val = {on}, }, //Replace mic: conf for L.in.R used
  { .ctl_name = “RECMIXL BST2 Switch”, .int_val = {off}, }, // close conf for micL used
  { .ctl_name = “RECMIXR BST2 Switch”, .int_val = {off}, }, // close conf for micR used
  { .ctl_name = “RECMIXL BST1 Switch”, .int_val = {off}, },
  { .ctl_name = “RECMIXR BST1 Switch”, .int_val = {off}, },
  { .ctl_name = “RECMIXL BST3 Switch”, .int_val = {off}, },
  { .ctl_name = “RECMIXR BST3 Switch”, .int_val = {off}, },
  { .ctl_name = “Stereo1 ADC L1 Mux”, .str_val = “ADC”, },
  { .ctl_name = “Stereo1 ADC R1 Mux”, .str_val = “ADC”, },
  { .ctl_name = “Stereo1 ADC MIXL ADC1 Switch”, .int_val = {on}, },
  { .ctl_name = “Stereo1 ADC MIXR ADC1 Switch”, .int_val = {on}, },
  { .ctl_name = “ADC Capture Switch”, .int_val = {on, on}, },
  { .ctl_name = “IN2 Boost”, .int_val = {2}, },
  { .ctl_name = “ADC Capture Volume”, .int_val = {47, 47}, },
  // if you feel vol is low/high, can adjust it from 37 to 80. [63 is copied from rt5616]
  { .ctl_name = “ADC Capture Volume”, .int_val = {63, 63}, }, // {57, 57} {47, 47} //这里调节音量值设置
  音频打开调用流程:
  #### route_pcm_open()
  #### -》 get_route_config(route)
  #### -》 route_set_controls()
  #### -》 route_pcm_close()
  #### -》 route_set_controls()
  -》
  如何debug
  1、通过看 kernel log 确认 alsa sound card 有没有注册。
  rk3288_mid:/ $ dmesg | grep ALSA -EC5
  [ 1.551902] I : [File] : drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c; [Line] : 417; [Func] : mali_module_init(); svn_rev_string_from_arm of this mali_ko is ‘-cf8da18’, rk_ko_ver is ‘5’, built at ‘11:19:29’, on ‘Jan 15 2020’。
  [ 1.553256] Mali: Mali device driver loaded
  [ 1.554211] of_get_named_gpiod_flags: parsed ‘gpios’ property of node ‘/rockchip-key/power-key[0]’ - status (0)
  [ 1.554274] of_get_named_gpiod_flags: parsed ‘gpios’ property of node ‘/rockchip-key/power-key[0]’ - status (0)
  [ 1.554741] input: rk29-keypad as /devices/platform/rockchip-key/input/input2
  [ 1.556689] ALSA device list:
  [ 1.556778] #0: realtek,rt5651-codec
  [ 1.556977] #1: rk,hdmiin-tc358749x-codec
  [ 1.557280] #2: rockchip,hdmi
  [ 1.557312] #3: rockchip-cdndp-sound
  [ 1.565498] mmc_host mmc2: Bus speed (slot 0) = 150000000Hz (slot req 150000000Hz, actual 150000000HZ div = 0)
  2、确认 route 是否正常
  声卡注册好之后确认 alsa route 是否正确
  通过命令 logcat -s alsa_route
  rk3288_mid:/ $ logcat -s alsa_route
  --------- beginning of system
  --------- beginning of main
  01-01 01:19:51.274 255 324 D alsa_route: route_set_controls() set route 24
  01-01 01:38:30.866 255 324 D alsa_route: route_info-》sound_card 0, route_info-》devices 0
  01-01 01:38:30.866 255 324 D alsa_route: route_set_controls() set route 0
  01-01 01:38:34.105 255 324 D alsa_route: route_set_controls() set route 24
  01-01 01:38:35.655 255 324 D alsa_route: route_info-》sound_card 0, route_info-》devices 0
  01-01 01:38:35.656 255 324 D alsa_route: route_set_controls() set route 0
  01-01 01:39:23.035 255 324 D alsa_route: route_set_controls() set route 24
  上面命令跑了两个路由 route 0 route 24。route的宏定义在alsa_audio.h中。
  文件:hardware/rockchip/audio$ vi tinyalsa_hal/alsa_audio.h
  62 typedef enum _AudioRoute {
  63 SPEAKER_NORMAL_ROUTE = 0,
  64 SPEAKER_INCALL_ROUTE, // 1
  65 SPEAKER_RINGTONE_ROUTE,
  66 SPEAKER_VOIP_ROUTE,
  67
  68 EARPIECE_NORMAL_ROUTE, // 4
  69 EARPIECE_INCALL_ROUTE,
  70 EARPIECE_RINGTONE_ROUTE,
  71 EARPIECE_VOIP_ROUTE,
  72
  73 HEADPHONE_NORMAL_ROUTE, // 8
  74 HEADPHONE_INCALL_ROUTE,
  75 HEADPHONE_RINGTONE_ROUTE,
  76 SPEAKER_HEADPHONE_NORMAL_ROUTE,
  77 SPEAKER_HEADPHONE_RINGTONE_ROUTE,
  78 HEADPHONE_VOIP_ROUTE,
  79
  80 HEADSET_NORMAL_ROUTE, // 14
  81 HEADSET_INCALL_ROUTE,
  82 HEADSET_RINGTONE_ROUTE,
  83 HEADSET_VOIP_ROUTE,
  84
  85 BLUETOOTH_NORMAL_ROUTE, // 18
  86 BLUETOOTH_INCALL_ROUTE,
  87 BLUETOOTH_VOIP_ROUTE,
  。..。..
  }AudioRoute;
举报

更多回帖

发帖
×
20
完善资料,
赚取积分