OpenHarmony(鸿蒙南向开辟)——标准系统方案之瑞芯微RK3568移植案例(上) ...

打印 上一主题 下一主题

主题 1001|帖子 1001|积分 3003

往期知识点记录:



  • 鸿蒙(HarmonyOS)应用层开辟(北向)知识点汇总
  • 鸿蒙(OpenHarmony)南向开辟保姆级知识点汇总~
  • 连续更新中……
本文章是基于瑞芯微RK3568芯片的DAYU200开辟板,举行标准系统相关功能的移植,主要包罗产物配置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,WIFI,BT,vibrator、sensor、图形显示模块的适配案例总结,以及相关功能的适配。
产物配置和目次规划

产物配置

在产物//productdefine/common/device目次下创建以rk3568名字定名的json文件,并指定CPU的架构。//productdefine/common/device/rk3568.json配置如下:
  1. {
  2.     "device_name": "rk3568",
  3.     "device_company": "rockchip",
  4.     "target_os": "ohos",
  5.     "target_cpu": "arm",
  6.     "kernel_version": "",
  7.     "device_build_path": "device/board/hihope/rk3568",
  8.     "enable_ramdisk": true,   //是否支持ramdisk二级启动
  9.     "build_selinux": true    // 是否支持selinux权限管理
  10. }
复制代码
在//productdefine/common/products目次下创建以产物名定名的rk3568.json文件。该文件用于形貌产物所使用的SOC 以及所需的子系统。配置如下
  1. {
  2.   "product_name": "rk3568",
  3.   "product_company" : "hihope",
  4.   "product_device": "rk3568",
  5.   "version": "2.0",
  6.   "type": "standard",
  7.   "parts":{
  8.     "ace:ace_engine_standard":{},
  9.     "ace:napi":{},
  10.     ...
  11.     "xts:phone_tests":{}
  12.   }
  13. }
复制代码
主要的配置内容包罗:
1.product_device:配置所使用的SOC。
2.type:配置系统的级别, 这里直接standard即可。
3.parts:系统必要启用的子系统。子系统可以简单理解为一块独立构建的功能块。
已界说的子系统可以在//build/subsystem_config.json中找到。固然你也可以定制子系统。
这里建议先拷贝Hi3516DV300开辟板的配置文件,删撤除hisilicon_products这个子系统。这个子系统为Hi3516DV300 SOC编译内核,不恰当rk3568。
目次规划

参考 Board和SoC解耦的设计思路 ,并把芯片适配目次规划为:
  1. device
  2. ├── board                                --- 单板厂商目录
  3. │   └── hihope                           --- 单板厂商名字:
  4. │       └── rk3568                       --- 单板名:rk3568,主要放置开发板相关的驱动业务代码
  5. └── soc                                                                         --- SoC厂商目录
  6.     └── rockchip                       --- SoC厂商名字:rockchip
  7.         └── rk3568                                                 --- SoC Series名:rk3568,主要为芯片原厂提供的一些方案,以及闭源库等
复制代码
<hr>
  1. vendor
  2. └── hihope                                       
  3.     └── rk3568                                  --- 产品名字:产品、hcs以及demo相关
复制代码
内核启动

二级启动

二级启动简单来说就是将之前直接挂载sytem,从system下的init启动,改成先挂载ramdsik,从ramdsik中的init 启动,做些必要的初始化动作,如挂载system,vendor等分区,然后切到system下的init 。
Rk3568适配主要是将主线编译出来的ramdisk 打包到boot_linux.img中,主要有以下工作:
1.使能二级启动
在productdefine/common/device/rk3568.json 中使能enable_ramdisk。
  1. {
  2.     "device_name": "rk3568",
  3.     "device_company": "hihope",
  4.     "target_os": "ohos",
  5.     "target_cpu": "arm",
  6.     "kernel_version": "",
  7.     "device_build_path": "device/hihope/build",
  8.     "enable_ramdisk": true,
  9.     "build_selinux": true
  10. }
复制代码
2.把主线编译出来的ramdsik.img 打包到boot_linux.img
配置:
由于rk 启动uboot 支持从ramdisk 启动,只必要在打包boot_linux.img 的配置文件中增长ramdisk.img ,因此没有使用主线的its格式,具体配置就是在内核编译脚本make-ohos.sh 中增长:
  1. function make_extlinux_conf()
  2. {
  3.         dtb_path=$1
  4.         uart=$2
  5.         image=$3
  6.        
  7.         echo "label rockchip-kernel-5.10" > ${EXTLINUX_CONF}
  8.         echo "        kernel /extlinux/${image}" >> ${EXTLINUX_CONF}
  9.         echo "        fdt /extlinux/${TOYBRICK_DTB}" >> ${EXTLINUX_CONF}
  10.         if [ "enable_ramdisk" == "${ramdisk_flag}" ]; then
  11.                 echo "        initrd /extlinux/ramdisk.img" >> ${EXTLINUX_CONF}
  12.         fi
  13.         cmdline="append earlycon=uart8250,mmio32,${uart} root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rw rootwait rootfstype=ext4"
  14.         echo "  ${cmdline}" >> ${EXTLINUX_CONF}
  15. }
复制代码
打包

增长了打包boot镜像的脚本make-boot.sh,供编译完ramdisk,打包boot 镜像时调用, 主要内容:
  1. genext2fs -B ${blocks} -b ${block_size} -d boot_linux -i 8192 -U boot_linux.img
复制代码
调用make-boot.sh 的修改可以参考如下pr:
https://gitee.com/openharmony/build/pulls/569/files
INIT配置

init相关配置请参考 启动子系统的规范要求即可
音频

RK3568 Audio总体结构图


ADM适配方案介绍

RK3568平台适配ADM框架图



  • ADM Drivers adapter
主要完成Codec/DMA/I2S驱动注册,使得ADM可以加载驱动节点;并注册ADM与Drivers交互的接口函数

  • ADM Drivers impl
主要完成ADM Drivers adapter接口函数的实现,以及Codec_config.hcs/dai_config.hcs等配置信息的获取,并注册到对应的设备

  • Linux Drivers
ADM Drivers impl可以直接阅读硬件手册,完成驱动端到端的配置;也可以借用Linux原生驱动实现与接口,减少开辟者工作量。
目次结构

  1. ./device/board/hihope/rk3568/audio_drivers
  2. ├── codec
  3. │   └── rk809_codec
  4. │       ├── include
  5. │       │   ├── rk809_codec_impl.h
  6. │       │   └── rk817_codec.h
  7. │       └── src
  8. │           ├── rk809_codec_adapter.c
  9. │           ├── rk809_codec_linux_driver.c
  10. │           └── rk809_codec_ops.c
  11. ├── dai
  12. │   ├── include
  13. │   │   ├── rk3568_dai_linux.h
  14. │   │   └── rk3568_dai_ops.h
  15. │   └── src
  16. │       ├── rk3568_dai_adapter.c
  17. │       ├── rk3568_dai_linux_driver.c
  18. │       └── rk3568_dai_ops.c
  19. ├── dsp
  20. │   ├── include
  21. │   │   └── rk3568_dsp_ops.h
  22. │   └── src
  23. │       ├── rk3568_dsp_adapter.c
  24. │       └── rk3568_dsp_ops.c
  25. ├── include
  26. │   ├── audio_device_log.h
  27. │   └── rk3568_audio_common.h
  28. └── soc
  29.     ├── include
  30.     │   └── rk3568_dma_ops.h
  31.     └── src
  32.         ├── rk3568_dma_adapter.c
  33.         └── rk3568_dma_ops.c
复制代码
RK3568适配ADM具体过程

梳理平台Audio框架

梳理目标平台的Audio结构,明确数据流与控制流通路。

  • 针对RK3568平台,Audio的结构相对简单见RK3568 Audio总体结构图,Codec作为一个独立设备。I2C完成对设备的控制,I2S完成Codec设备与CPU之间的交互。
  • 联合原理图整理I2S通道号,对应的引脚编号;I2C的通道号,地点等硬件信息。
  • 获取Codec对应的datasheet,以及RK3568平台的Datasheet(包含I2S/DMA通道等寄存器的介绍)。
熟悉并了解ADM结构

ADM结构框图如下,Audio Peripheral Drivers和Platform Drivers为平台适配必要完成的工作。

联合第1步梳理出来的Audio结构分析,Audio Peripheral Drivers包含Rk809的驱动,Platform Drivers包含DMA驱动和I2S驱动。
    必要适配的驱动   ADM对应模块   接口文件路径         RK809驱动   Accessory   drivers/framework/include/audio/audio_accessory_if.h       DMA驱动   platform   drivers/framework/include/audio/audio_platform_if.h       I2S驱动   DAI   drivers/framework/include/audio/audio_dai_if.h.h   搭建驱动代码框架

配置HCS文件

在device_info.hcs文件中Audio下注册驱动节点
  1.         audio :: host {
  2.             hostName = "audio_host";
  3.             priority = 60;
  4.             device_dai0 :: device {
  5.                 device0 :: deviceNode {
  6.                     policy = 1;
  7.                     priority = 50;
  8.                     preload = 0;
  9.                     permission = 0666;
  10.                     moduleName = "DAI_RK3568";
  11.                     serviceName = "dai_service";
  12.                     deviceMatchAttr = "hdf_dai_driver";
  13.                 }
  14.             }
  15.             device_codec :: device {
  16.                 device0 :: deviceNode {
  17.                     policy = 1;
  18.                     priority = 50;
  19.                     preload = 0;
  20.                     permission = 0666;
  21.                     moduleName = "CODEC_RK809";
  22.                     serviceName = "codec_service_0";
  23.                     deviceMatchAttr = "hdf_codec_driver";
  24.                 }
  25.             }
  26.             device_codec_ex :: device {
  27.                 device0 :: deviceNode {
  28.                     policy = 1;
  29.                     priority = 50;
  30.                     preload = 0;
  31.                     permission = 0666;
  32.                     moduleName = "CODEC_RK817";
  33.                     serviceName = "codec_service_1";
  34.                     deviceMatchAttr = "hdf_codec_driver_ex";
  35.                 }
  36.             }
  37.             device_dsp :: device {
  38.                 device0 :: deviceNode {
  39.                     policy = 1;
  40.                     priority = 50;
  41.                     preload = 0;
  42.                     permission = 0666;
  43.                     moduleName = "DSP_RK3568";
  44.                     serviceName = "dsp_service_0";
  45.                     deviceMatchAttr = "hdf_dsp_driver";
  46.                 }
  47.             }
  48.             device_dma :: device {
  49.                 device0 :: deviceNode {
  50.                     policy = 1;
  51.                     priority = 50;
  52.                     preload = 0;
  53.                     permission = 0666;
  54.                     moduleName = "DMA_RK3568";
  55.                     serviceName = "dma_service_0";
  56.                     deviceMatchAttr = "hdf_dma_driver";
  57.                 }
  58.             }
  59.             ......
  60.         }
  61. c
复制代码
根据接入的设备,选择Codec节点照旧Accessory节点,配置硬件设备对应的私有属性(包含寄存器首地点,相关control寄存器地点)涉及Codec_config.hcs和DAI_config.hcs
配置相关介绍见 Audio hcs配置章节以及ADM框架的audio_parse模块代码。
codec/accessory模块

1.将驱动注册到HDF框架中,代码片段如下,启动moduleName与HCS文件的中moduleName一致
  1. struct HdfDriverEntry g_codecDriverEntry = {
  2.    .moduleVersion = 1,
  3.    .moduleName = "CODEC_HI3516",
  4.    .Bind = CodecDriverBind,
  5.    .Init = CodecDriverInit,
  6.    .Release = CodecDriverRelease,
  7. };
  8. HDF_INIT(g_codecDriverEntry);
复制代码
2.Codec模块必要添补:
g_codecData:codec设备的操纵函数集和私有数据集。
g_codecDaiDeviceOps:codecDai的操纵函数集,包罗启动传输和参数配置等函数接口。
g_codecDaiData:codec的数字音频接口的操纵函数集和私有数据集。
3.完成 bind、init和release函数的实现
4.验证
在bind和init函数加调试日志,编译版本并获取系统系统日志:
  1. [    1.548624] [E/"rk809_codec_adapter"]  [Rk809DriverBind][line:258]: enter
  2. [    1.548635] [E/"rk809_codec_adapter"]  [Rk809DriverBind][line:260]: success
  3. [    1.548655] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:270]: enter
  4. [    1.549050] [E/"rk809_codec_adapter"]  [GetServiceName][line:226]: enter
  5. [    1.549061] [E/"rk809_codec_adapter"]  [GetServiceName][line:250]: success
  6. [    1.549072] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:316]: g_chip->accessory.drvAccessoryName = codec_service_1
  7. [    1.549085] [E/audio_core]  [AudioSocRegisterDai][line:86]: Register [accessory_dai] success.
  8. [    1.549096] [E/audio_core]  [AudioRegisterAccessory][line:120]: Register [codec_service_1] success.
  9. [    1.549107] [E/"rk809_codec_adapter"]  [Rk809DriverInit][line:323]: success!
复制代码
DAI模块
1.将I2S驱动注册到HDF框架中,代码片段如下,启动moduleName与HCS文件的中moduleName一致
  1. struct HdfDriverEntry g_daiDriverEntry = {
  2.     .moduleVersion = 1,
  3.     .moduleName = "DAI_RK3568",
  4.     .Bind = DaiDriverBind,
  5.     .Init = DaiDriverInit,
  6.     .Release = DaiDriverRelease,
  7. };
  8. HDF_INIT(g_daiDriverEntry);
复制代码
2.DAI模块添补:
  1. struct AudioDaiOps g_daiDeviceOps = {
  2.     .Startup = Rk3568DaiStartup,
  3.     .HwParams = Rk3568DaiHwParams,
  4.     .Trigger = Rk3568NormalTrigger,
  5. };
  6. struct DaiData g_daiData = {
  7.     .Read = Rk3568DeviceReadReg,
  8.     .Write = Rk3568DeviceWriteReg,
  9.     .DaiInit = Rk3568DaiDeviceInit,
  10.     .ops = &g_daiDeviceOps,
  11. };
复制代码
3.完成 bind、init和release函数的实现
4.验证
在bind/init函数加调试日志,编译版本并获取系统系统日志
  1. [    1.549193] [I/device_node] launch devnode dai_service
  2. [    1.549204] [E/HDF_LOG_TAG]  [DaiDriverBind][line:38]: entry!
  3. [    1.549216] [E/HDF_LOG_TAG]  [DaiDriverBind][line:55]: success!
  4. [    1.549504] [E/audio_core]  [AudioSocRegisterDai][line:86]: Register [dai_service] success.
  5. [    1.549515] [E/HDF_LOG_TAG]  [DaiDriverInit][line:116]: success.
复制代码
Platform模块
1.将DMA驱动注册到HDF框架中,代码片段如下,启动moduleName与HCS文件的中moduleName一致
  1. struct HdfDriverEntry g_platformDriverEntry = {
  2.     .moduleVersion = 1,
  3.     .moduleName = "DMA_RK3568",
  4.     .Bind = PlatformDriverBind,
  5.     .Init = PlatformDriverInit,
  6.     .Release = PlatformDriverRelease,
  7. };
  8. HDF_INIT(g_platformDriverEntry);
复制代码
2.DMA模块必要添补:
  1. struct AudioDmaOps g_dmaDeviceOps = {
  2.     .DmaBufAlloc = Rk3568DmaBufAlloc,
  3.     .DmaBufFree = Rk3568DmaBufFree,
  4.     .DmaRequestChannel = Rk3568DmaRequestChannel,
  5.     .DmaConfigChannel = Rk3568DmaConfigChannel,
  6.     .DmaPrep = Rk3568DmaPrep,
  7.     .DmaSubmit = Rk3568DmaSubmit,
  8.     .DmaPending = Rk3568DmaPending,
  9.     .DmaPause = Rk3568DmaPause,
  10.     .DmaResume = Rk3568DmaResume,
  11.     .DmaPointer = Rk3568PcmPointer,
  12. };
  13. struct PlatformData g_platformData = {
  14.     .PlatformInit = AudioDmaDeviceInit,
  15.     .ops = &g_dmaDeviceOps,
  16. };
复制代码
3.完成 bind、init和release函数的实现
4.验证
在bind和init函数加调试日志,编译版本并获取系统系统日志
  1. [    1.548469] [E/rk3568_platform_adapter]  [PlatformDriverBind][line:42]: entry!
  2. [    1.548481] [E/rk3568_platform_adapter]  [PlatformDriverBind][line:58]: success!
  3. [    1.548492] [E/rk3568_platform_adapter]  [PlatformDriverInit][line:100]: entry.
  4. [    1.548504] [E/rk3568_platform_adapter]  [PlatformGetServiceName][line:67]: entry!
  5. [    1.548515] [E/rk3568_platform_adapter]  [PlatformGetServiceName][line:91]: success!
  6. [    1.548528] [E/audio_core]  [AudioSocRegisterPlatform][line:63]: Register [dma_service_0] success.
  7. [    1.548536] [E/rk3568_platform_adapter]  [PlatformDriverInit][line:119]: success.
复制代码
驱动适配

code/accessory模块


  • 读取DTS文件,获取到对应设备节点,使用Linux原生的驱动注册函数,获取到对应device。
  1. static int rk817_platform_probe(struct platform_device *pdev) {
  2.     rk817_pdev = pdev;
  3.     dev_info(&pdev->dev, "got rk817-codec platform_device");
  4.     return 0;
  5. }
  6. static struct platform_driver rk817_codec_driver = {
  7.         .driver = {
  8.                    .name = "rk817-codec",                     // codec node in dts file
  9.                    .of_match_table = rk817_codec_dt_ids,
  10.                    },
  11.         .probe = rk817_platform_probe,
  12.         .remove
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表