编辑
2025-01-20
工作知识
0
请注意,本文编写于 137 天前,最后修改于 137 天前,其中某些信息可能已经过时。

目录

一、声卡组成情况
二、代码位置
三、具体联系
3.1 ADM hdf driver
3.2 vendor audio hdf driver
3.3 ADM和vendor audio驱动的联系
3.4 dma 的hcs config
3.5 dai 的hcs config
3.6 codec的hcs config

我们根据dayu200的开发板的研究,分析了dayu200的音频是通过ADM的方案实现,如下是具体分析过程

一、声卡组成情况

dayu200的声卡接入方式如下:

image.png

二、代码位置

针对左侧,需要实现dma传输的驱动,路径如下:

device/board/hihope/rk3568/audio_drivers/soc/src/rk3568_dma_adapter.c

对于I2S1,需要实现I2S1的驱动功能,路径如下:

device/board/hihope/rk3568/audio_drivers/dai/src/rk3568_dai_adapter.c

对于RK809,需要实现RK809的驱动功能,路径如下:

device/board/hihope/rk3568/audio_drivers/codec/rk809_codec/src/rk809_codec_adapter.c

对于hdf的ADM框架,代码如下(以Linux路径为例):

out/kernel/src_tmp/linux-5.10/drivers/hdf/framework/model/audio

对于匹配驱动,使用hcs的方式,代码如下:

vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs

三、具体联系

根据上面的代码仓库描述,我们需要知道如下:

  • ADM是openharmony实现的hdf driver
  • 厂商可以在device board里面实现自己的audio driver
  • hdf driver的匹配通过hcs的规则来实现

所以根据上述的四条,可以如下解析:

3.1 ADM hdf driver

/* HdfDriverEntry definitions */ struct HdfDriverEntry g_audioDriverEntry = { .moduleVersion = 1, .moduleName = "HDF_AUDIO", .Bind = AudioDriverBind, .Init = AudioDriverInit, .Release = AudioDriverRelease, }; HDF_INIT(g_audioDriverEntry); /* HdfDriverEntry definitions */ struct HdfDriverEntry g_audioStreamEntry = { .moduleVersion = 1, .moduleName = "HDF_AUDIO_STREAM", .Bind = AudioStreamBind, .Init = AudioStreamInit, .Release = AudioStreamRelease, }; HDF_INIT(g_audioStreamEntry); /* HdfDriverEntry definitions */ struct HdfDriverEntry g_audioControlEntry = { .moduleVersion = 1, .moduleName = "HDF_AUDIO_CONTROL", .Bind = AudioControlBind, .Init = AudioControlInit, .Release = AudioControlRelease, }; HDF_INIT(g_audioControlEntry);

可以知道,ADM需要至少注册三个必要类型的驱动,一个是audio_host,一个是audio_control_dispatch,一个是audio_stream_dispatch。对于的hcs如下:

device_primary :: deviceNode { policy = 2; priority = 60; preload = 0; permission = 0666; moduleName = "HDF_AUDIO"; deviceMatchAttr = "hdf_audio_driver_0"; serviceName = "hdf_audio_codec_primary_dev0"; } device0 :: deviceNode { policy = 2; priority = 80; preload = 0; permission = 0666; moduleName = "HDF_AUDIO_STREAM"; serviceName = "hdf_audio_render"; } device1 :: deviceNode { policy = 2; priority = 80; preload = 0; permission = 0666; moduleName = "HDF_AUDIO_STREAM"; serviceName = "hdf_audio_capture"; } device0 :: deviceNode { policy = 2; priority = 80; preload = 0; permission = 0666; moduleName = "HDF_AUDIO_CONTROL"; serviceName = "hdf_audio_control"; }

这样,在系统开机的时候,会通过hdf device manager驱动管理和注册,调用这些驱动的init函数

3.2 vendor audio hdf driver

对于厂商实现的audio_driver,这里主要是dma,i2s和codec,如下

/* HdfDriverEntry definitions */ struct HdfDriverEntry g_platformDriverEntry = { .moduleVersion = 1, .moduleName = "DMA_RK3568", .Bind = PlatformDriverBind, .Init = PlatformDriverInit, .Release = PlatformDriverRelease, }; HDF_INIT(g_platformDriverEntry); /* HdfDriverEntry definitions */ struct HdfDriverEntry g_daiDriverEntry = { .moduleVersion = 1, .moduleName = "DAI_RK3568", .Bind = DaiDriverBind, .Init = DaiDriverInit, .Release = DaiDriverRelease, }; HDF_INIT(g_daiDriverEntry); /* HdfDriverEntry definitions */ struct HdfDriverEntry g_Rk809DriverEntry = { .moduleVersion = 1, .moduleName = "CODEC_RK809", .Bind = Rk809DriverBind, .Init = Rk809DriverInit, .Release = RK809DriverRelease, }; HDF_INIT(g_Rk809DriverEntry);

这三个驱动,对于的hcs配置如下

device_primary :: deviceNode { policy = 1; priority = 50; preload = 0; permission = 0666; moduleName = "DAI_RK3568"; serviceName = "dai_service"; deviceMatchAttr = "hdf_dai_driver"; } device_primary :: deviceNode { policy = 1; priority = 50; preload = 0; permission = 0666; moduleName = "CODEC_ES8388"; serviceName = "codec_service_0"; deviceMatchAttr = "hdf_codec_driver_0"; } device_primary :: deviceNode { policy = 1; priority = 50; preload = 0; permission = 0666; moduleName = "DMA_RK3568"; serviceName = "dma_service_0"; deviceMatchAttr = "hdf_dma_driver"; }

这样,在系统开机的时候,会通过hdf device manager驱动管理和注册,调用这些驱动的init函数

3.3 ADM和vendor audio驱动的联系

通过hcs的card_controller可以将其联系起来,如下:

controller_0x120c1000 :: card_controller { match_attr = "hdf_audio_driver_0"; serviceName = "hdf_audio_codec_primary_dev0"; codecName = "codec_service_0"; platformName = "dma_service_0"; cpuDaiName = "dai_service"; codecDaiName = "codec_dai"; dspName = "dsp_service_0"; dspDaiName = "dsp_dai"; }

3.4 dma 的hcs config

对于dma而言,需要dma的相关配置,openharmony目前dma都在代码配置,hcs比较少,如下

controller_0x120c1010 :: dma_controller { match_attr = "hdf_dma_driver"; serviceName = "dma_service_0"; idInfo { chipName = "/i2s@fe410000"; chipIdRegister = 0xfe410000; chipIdSize = 0x1000; } regConfig { /* reg: register address rreg: register address shift: shift bits rshift: rshift bits min: min value max: max value mask: mask of value invert: enum InvertVal 0-uninvert 1-invert value: value reg, rreg, shift, rshift, min, max, mask, invert value */ daiStartupSeqConfig = [ 0x00, 0x00, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x0, //Transmit Operation Init ]; } }

3.5 dai 的hcs config

对于i2s而言,我们需要配置i2s1的基本信息,并且填充startup/hwparam/trigger的寄存器配置,如下

daiStartupSeqConfig = [ 0x00, 0x00, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x7200000f, //Transmit Operation Init 0x04, 0x04, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x01c8000f, //Receive Operation Init 0x08, 0x08, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x00001f1f, //Clock Generation Init 0x10, 0x10, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x001f0000, //DMA Control Init 0x14, 0x14, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x01f00000, //Interrupt Control Init 0x1C, 0x1C, 0, 0, 0, 0x3, 0x3, 0, 0, //XFER Init 0x30, 0x30, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x00003eff, //TDM Transmit Init 0x34, 0x34, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x00003eff, //TDM Receive Init 0x38, 0x38, 0, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0x00000707 //Clock Divider Init ]; daiParamsSeqConfig = [ 0x08, 0x08, 8, 8, 0x1F, 0xFF, 0xFF, 0, 0x0, // I2S_CKR_RSD 0x08, 0x08, 0, 0, 0x1F, 0xFF, 0xFF, 0, 0x0, // I2S_CKR_TSD 0x38, 0x38, 8, 8, 0x00, 0xFF, 0xFF, 0, 0x0, // I2S_CLKDIV_RX_MDIV 0x38, 0x38, 0, 0, 0x00, 0xFF, 0xFF, 0, 0x0, // I2S_CLKDIV_TX_MDIV 0x08, 0x08, 27, 27, 0x0, 0x1, 0x1, 0, 0x0, // I2S_CKR_MSS 0x08, 0x08, 26, 26, 0x0, 0x1, 0x1, 0, 0x0, // I2S_CKR_CKP 0x08, 0x08, 25, 25, 0x0, 0x1, 0x1, 0, 0x0, // I2S_CKR_RLP 0x08, 0x08, 24, 24, 0x0, 0x1, 0x1, 0, 0x0, // I2S_CKR_TLP ]; daiTriggerSeqConfig = [ 0x10, 0x10, 24, 24, 0x0, 0x1, 0x1, 0, 0x1, // I2S_DMACR_RDE 0x10, 0x10, 8, 8, 0x0, 0x1, 0x1, 0, 0x1, // I2S_DMACR_TDE 0x14, 0x14, 17, 17, 0x0, 0x1, 0x1, 0, 0x0, // I2S_INTCR_RXOIE 0x14, 0x14, 16, 16, 0x0, 0x1, 0x1, 0, 0x0, // I2S_INTCR_RXFIE 0x14, 0x14, 1, 1, 0x0, 0x1, 0x1, 0, 0x0, // I2S_INTCR_TXUIE 0x14, 0x14, 0, 0, 0x0, 0x1, 0x1, 0, 0x0 // I2S_INTCR_TXEIE ];

3.6 codec的hcs config

对于codec,这里是rk809,我们需要配置rk809的基本信息,如startup/hwparam/trigger,sapm寄存器,init寄存器,播放和录制默认配置,如下

controller_0x120c1030 :: codec_controller { match_attr = "hdf_codec_driver_0"; serviceName = "codec_service_0"; codecDaiName = "codec_dai"; hwInfo = [ /* Playback/Captrue, formats, rates, rate_min, rate_max, channels_min, channels_max, buffer_bytes_max, period_bytes_min, period_bytes_max, periods_min, periods_max */ 1, 0xF, 0xFF, 8000, 96000, 1, 2, 1, 2, 3, 4, 5, 2, 0xF, 0xFF, 8000, 96000, 1, 2, 1, 2, 3, 4, 5, ]; regConfig { /* reg: register address rreg: register address shift: shift bits rshift: rshift bits min: min value max: max value mask: mask of value invert: enum InvertVal 0-uninvert 1-invert value: value */ /* reg, value */ initSeqConfig = [ 0x13, 0xf4, 0x15, 0xff, 0x17, 0x40, 0x18, 0xc8, 0x1e, 0x00, 0x27, 0x3f, 0x29, 0x99, 0x2f, 0x03, 0x30, 0x06, 0x35, 0x02, 0x38, 0x10, 0x3c, 0x0F, 0x3d, 0x80, 0x3e, 0x0f, 0x3f, 0x11, 0x40, 0xa5, 0x41, 0x77, 0x42, 0x04, 0x43, 0x58, 0x44, 0x2d, 0x45, 0x0c, 0x46, 0xa5, 0x47, 0x00, 0x48, 0x00, 0x4b, 0x0f, 0x4c, 0x20, 0x4e, 0x0f, 0x4f, 0x00, ]; controlsConfig = [ /*array index, iface, mixer/mux, enable,*/ 0, 2, 0, 1, 1, 2, 0, 1, 2, 2, 0, 1, 3, 2, 0, 1, 4, 2, 0, 1, 5, 2, 0, 1, 8, 2, 0, 1, 9, 2, 0, 1, ]; /* reg, rreg, shift, rshift, min, max, mask, invert, value */ ctrlParamsSeqConfig = [ 0x31, 0x32, 0, 0, 0x00, 0xFF, 0xFF, 1, 0x00, // DACL/R Playback Volume 0x1a, 0x1b, 0, 0, 0x00, 0xFF, 0xFF, 1, 0x00, // ADCL/R Capture Volume 0x38, 0x38, 0, 0, 0x0, 0x1, 0x1, 0, 0x0, // DAC Playback Mute 0x27, 0x27, 6, 6, 0x0, 0x1, 0x1, 0, 0x0, // ADCL/R Capture Mute 0x29, 0x29, 4, 4, 0x0, 0xF, 0xF, 0, 0x9, // Mic Left Gain 0x29, 0x29, 0, 0, 0x0, 0xF, 0xF, 0, 0x9, // Mic Right Gain 0x4a, 0x4a, 2, 2, 0x0, 0x2, 0x3, 0, 0x0, // Render Channel Mode 0x4d, 0x4d, 2, 2, 0x0, 0x2, 0x3, 0, 0x0, // Captrue Channel Mode ]; /* reg, rreg, shift, rshift, min, max, mask, invert, value */ daiParamsSeqConfig = [ 0x45, 0x45, 0, 0, 0x0, 0xFF, 0xFF, 0, 0x0C, // PLL_PREDIV_BIT 0x35, 0x35, 0, 0, 0x0, 0x7, 0x7, 0, 0x2, // DAC_Sample_rate 0x1e, 0x1e, 0, 0, 0x0, 0x7, 0x7, 0, 0x2, // ADC_Sample_rate 0x4e, 0x4e, 0, 0, 0x0, 0x17, 0x1F, 0, 0x0F, // TX_datawidth 0x4b, 0x4b, 0, 0, 0x0, 0x17, 0x1F, 0, 0x0F, // RX_datawidth 0x15, 0x15, 0x0, 0x0, 0x0, 0xf, 0xf, 0, 0x0, // rx clk enable 0x15, 0x15, 0x4, 0x4, 0x0, 0xf, 0xf, 0, 0x0, // tx clk enable ]; ctrlSapmParamsSeqConfig = [ 0x27, 0x27, 5, 5, 0x00, 0x1, 0x1, 1, 0x00, //LPGA MIC -- connect MIC1 0x27, 0x27, 4, 4, 0x00, 0x1, 0x1, 1, 0x00, //RPGA MIC -- connect MIC2 0x2F, 0x2F, 2, 2, 0x00, 0x1, 0x1, 1, 0x00, //Speaker1 Switch -- connect speaker 0x2F, 0x2F, 1, 1, 0x00, 0x1, 0x1, 1, 0x00, //Headphone1 Switch -- connect hpl 0x2F, 0x2F, 0, 0, 0x00, 0x1, 0x1, 1, 0x00, //Headphone2 Switch -- connect hpr ]; /* reg is 0xFFFF: component has no sapm register bit sapmType, compNameIndex, reg, mask, shift, invert, kcontrolNews, kcontrolsNum */ sapmComponent = [ 10, 0, 0x18, 0x1, 7, 1, 0, 0, //ADCL 10, 1, 0x18, 0x1, 6, 1, 0, 0, //ADCR 11, 32, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //DAC1 11, 33, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //DAC2 11, 34, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //DAC3 6, 52, 0xFFFF, 0xFFFF, 0, 0, 3, 1, //SPKL PGA 6, 54, 0xFFFF, 0xFFFF, 0, 0, 4, 1, //HPL PGA 6, 55, 0xFFFF, 0xFFFF, 0, 0, 5, 1, //HPR PGA 15, 6, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //SPK 14, 10, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //HPL 14, 11, 0xFFFF, 0xFFFF, 0, 0, 0, 0, //HPR 6, 4, 0xFFFF, 0xFFFF, 6, 0, 1, 1, //LPGA 6, 5, 0xFFFF, 0xFFFF, 6, 0, 2, 1, //RPGA 13, 40, 0xFFFF, 0xFFFF, 6, 0, 0, 0, //MIC1 13, 41, 0x4d, 0x1, 1, 0, 0, 0 //MIC2 ]; /*array index, iface, mixer/mux, enable*/ sapmConfig = [ 0, 2, 0, 1, 1, 2, 0, 1, 24, 2, 0, 1, 28, 2, 0, 1, 29, 2, 0, 1 ]; } }

至此,dayu200的基本音频方案ADM的情况已经梳理清楚