ToB企服应用市场:ToB评测及商务社交产业平台

标题: OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(上) [打印本页]

作者: 杀鸡焉用牛刀    时间: 2024-10-20 00:29
标题: OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(上)
往期推文全新看点:


本文章是基于瑞芯微RK3566芯片的khdvk_3566b开发板,进行标准系统相干功能的移植,主要包括产品设置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,WIFI,BT,vibrator、sensor、图形表现模块的适配案例总结,以及相干功能的适配。
产品设置和目录规划

产品设置

在产品//vendor/目录下创建以kaihong名字命名的文件夹,并在kaihong文件夹下面新建产品命的文件夹khdvk_3566b。
在//vendor/kaihong/khdvk_3566b目录下创建config.json文件。该文件用于形貌产品所利用的SOC以及所需的子系统。设置如下
  1. {
  2.   "product_name": "khdvk_3566b",
  3.   "device_company": "kaihong",
  4.   "device_build_path": "device/board/kaihong/build",
  5.   "target_cpu": "arm",
  6.   "type": "standard",
  7.   "version": "3.0",
  8.   "board": "khdvk_3566b",
  9.   "enable_ramdisk": true,//是否支持ramdisk二级启动
  10.   "build_selinux": true,// 是否支持selinux权限管理
  11.   "subsystems": [
  12.     {
  13.       "subsystem": "arkui",
  14.       "components": [
  15.         {
  16.           "component": "ace_engine_standard",
  17.           "features": []
  18.         },
  19.         {
  20.           "component": "napi",
  21.           "features": []
  22.         }
  23.       ]
  24.     },
  25.     .
  26.     .
  27.     .
  28.     {
  29.       "subsystem": "thirdparty",
  30.       "components": [
  31.         {
  32.           "component": "musl",
  33.           "features": []
  34.         }
  35.       ]
  36.     }
  37.   ]
  38. }
复制代码
主要的设置内容包括:
已界说的子系统可以在//build/subsystem_config.json中找到。当然你也可以定制子系统。
这里建议先拷贝Hi3516DV300开发板的设置文件,删除掉hisilicon_products这个子系统。这个子系统为Hi3516DV300 SOC编译内核,不得当rk3566
目录规划

参考https://gitee.com/openharmony-sig/sig-content/blob/master/devboard/docs/board-soc-arch-design.md,并把芯片适配目录规划为:
  1. device
  2. ├── board                                --- 单板厂商目录
  3. │   └── kaihong                          --- 单板厂商名字:
  4. │       └── khdvk_3566b                  --- 单板名:khdvk_3566b,主要放置开发板相关的驱动业务代码
  5. └── soc                                  --- SoC厂商目录
  6.     └── rockchip                         --- SoC厂商名字:rockchip
  7.         └── rk3566                       --- SoC Series名:rk3566,主要为芯片原厂提供的一些方案,以及闭源库等
  8. vendor
  9. └── kaihong                              --- 开发产品样例厂商目录
  10.     └── khdvk_3566b                      --- 产品名字:产品、hcs以及demo相关
复制代码
内核启动

二级启动

二级启动简朴来说就是将之前直接挂载sytem,从system下的init启动,改成先挂载ramdsik,从ramdsik中的init 启动,做些须要的初始化动作,如挂载system,vendor平分区,然后切到system下的init。
Rk3566适配主要是将主线编译出来的ramdisk打包到boot.img中,主要有以下工作:
1.使能二级启动
在//vendor/kaihong/khdvk_3566b/config.json中使能enable_ramdisk。
  1. {
  2.   "product_name": "khdvk_3566b",
  3.   "device_company": "kaihong",
  4.   "device_build_path": "device/board/kaihong/build",
  5.   "target_cpu": "arm",
  6.   "type": "standard",
  7.   "version": "3.0",
  8.   "board": "khdvk_3566b",
  9.   "enable_ramdisk": true,//是否支持ramdisk二级启动
  10.   "build_selinux": true,// 是否支持selinux权限管理
复制代码
2.把主线编译出来的ramdsik.img 打包到boot.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.     echo "label rockchip-kernel-5.10" > ${EXTLINUX_CONF}
  7.     echo "    kernel /extlinux/${image}" >> ${EXTLINUX_CONF}
  8.     echo "    fdt /extlinux/${TOYBRICK_DTB}" >> ${EXTLINUX_CONF}
  9.     if [ "enable_ramdisk" == "${ramdisk_flag}" ]; then
  10.         echo "    initrd /extlinux/ramdisk.img" >> ${EXTLINUX_CONF}
  11.     fi
  12.     cmdline="append earlycon=uart8250,mmio32,${uart} root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rw rootwait rootfstype=ext4"
  13.     echo "  ${cmdline}" >> ${EXTLINUX_CONF}
  14. }
复制代码
打包

增加了打包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相干设置请参考 启动子系统的规范要求 即可
音频

khdvk_3566b Audio硬件结构图


khdvk_3566b平台Audio驱动框架图


实现Audio HAL层驱动(HDI接口适配),给Audio服务(frameworks)提供所需的音频硬件驱动本领接口。包含 Audio Manager、Audio Adapter、Audio Control、Audio Capture、Audio Render等接口对象。
共同内核中的Audio Driver Model利用,实现音频硬件的控制、灌音数据的读取、播放数据的写入。它里面包括Stream_ctrl_common 通用层,主要是为了和上层的audio HDI adapter层进行对接。
音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,对于Codec和DSP设备厂商来说,可根据ADM模块提供的向下统一接口适配各自的驱动代码,就可以实现快速开发和适配OpenHarmony系统。
接收lib层的控制指令并将控制指令分发到驱动层。
接收lib层的数据并将数据分发到驱动层
多声卡管理模块,每个声卡含有Dai、Platform、Codec、Accessory、Dsp、SAPM模块。
驱动适配层。
电源管理模块,对整个ADM电源进行功耗计谋优化。
Audio 驱动开发

这里以khdvk_3566b为例,讲述Audio驱动开发,其涉及到的模块驱动主要有:Codec驱动、platform驱动、Dai驱动。
相干代码路径如下:
  1. device/board/kaihong/khdvk_3566b/audio_drivers/codec/rk809_codec/
  2. device/board/kaihong/khdvk_3566b/audio_drivers/codec/dai/
  3. device/board/kaihong/khdvk_3566b/audio_drivers/codec/soc/
复制代码
HDF HCS设置路径如下:
  1. vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/
  2. vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/
复制代码
Audio 驱动开发流程:
  1. step1:配置各个模块的HCS
  2. step2:修改各个模块的编译文件
  3. step3:配置各个模块的函数操作集
  4. step4:进行功能调试
复制代码
Audio驱动开发实例

codec驱动开发实例

代码路径:
device/board/kaihong/khdvk_3566b/audio_drivers/codec/rk809_codec/
  1. .moduleVersion = 1,
  2. .moduleName = "CODEC_RK809",
  3. .Bind = Rk809DriverBind,
  4. .Init = Rk809DriverInit,
  5. .Release = RK809DriverRelease,
  6. };
  7. HDF_INIT(g_Rk809DriverEntry);
复制代码
g_codecData:codec设备的操作函数集和私有数据集。
g_codecDaiDeviceOps:codecDai的操作函数集,包括启动传输和参数设置等函数接口。
g_codecDaiData:codec的数字音频接口的操作函数集和私有数据集。
  1. struct CodecData g_rk809Data = {
  2.     .Init = Rk809DeviceInit,
  3.     .Read = RK809CodecReadReg,
  4.     .Write = Rk809CodecWriteReg,
  5. };
  6. struct AudioDaiOps g_rk809DaiDeviceOps = {
  7.     .Startup = Rk809DaiStartup,
  8.     .HwParams = Rk809DaiHwParams,
  9.     .Trigger = Rk809NormalTrigger,
  10. };
  11. struct DaiData g_rk809DaiData = {
  12.     .DaiInit = Rk809DaiDeviceInit,
  13.     .ops = &g_rk809DaiDeviceOps,
  14. };
复制代码
1> CodecData结构体操作函数的实现
  1. int32_t Rk809DeviceInit(struct AudioCard *audioCard, const struct CodecDevice *device)
  2. {
  3.      ......  
  4.     //get和set功能注册
  5.     if (CodecSetCtlFunc(device->devData, RK809GetCtrlOps, RK809SetCtrlOps) != HDF_SUCCESS) {
  6.        AUDIO_DRIVER_LOG_ERR("AudioCodecSetCtlFunc failed.");
  7.        return HDF_FAILURE;
  8.     }
  9.    //codec默认寄存器的初始化
  10.    ret = RK809RegDefaultInit(device->devData->regCfgGroup);
  11.    ......
  12.    if (AudioAddControls(audioCard, device->devData->controls, device->devData->numControls) != HDF_SUCCESS) {
  13.        AUDIO_DRIVER_LOG_ERR("add controls failed.");
  14.        return HDF_FAILURE;
  15.    }
  16.    ......
  17. }
  18. /*读寄存器接口*/
  19. int32_t RK809CodecReadReg(const struct CodecDevice *codec, uint32_t reg, uint32_t *val)
  20. {
  21.     ......
  22.     if (Rk809DeviceRegRead(reg, val)) {
  23.         AUDIO_DRIVER_LOG_ERR("read register fail: [%04x]", reg);
  24.         return HDF_FAILURE;
  25.     }
  26.    return HDF_SUCCESS;
  27. }
  28. /*写寄存器接口*/
  29. int32_t Rk809CodecWriteReg(const struct CodecDevice *codec, uint32_t reg, uint32_t value)
  30. {
  31.     if (Rk809DeviceRegWrite(reg, value)) {
  32.         AUDIO_DRIVER_LOG_ERR("write register fail: [%04x] = %04x", reg, value);
  33.         return HDF_FAILURE;
  34.     }
  35.     return HDF_SUCCESS;
  36. }
复制代码
2> g_rk809DaiDeviceOps结构体的具体实现
  1. /*Rk809DaiStartup为启动时的一些设置*/
  2. int32_t Rk809DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
  3. {
  4.     ......
  5.     ret = RK809WorkStatusEnable(device->devData->regCfgGroup);
  6.     ......
  7. }
  8. /*Rk809DaiHwParams为参数配置,包括采样率、位宽等。*/
  9. int32_t Rk809DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
  10. {
  11.     ......
  12.     ret = AudioFormatToBitWidth(param->format, &bitWidth);
  13.     codecDaiParamsVal.frequencyVal = param->rate;
  14.     codecDaiParamsVal.DataWidthVal = bitWidth;
  15.     ret =  RK809DaiParamsUpdate(card->rtd->codecDai->devData->regCfgGroup, codecDaiParamsVal);
  16.     ......
  17. }
  18. /*PCM流控制寄存器相关配置*/
  19. int32_t Rk809NormalTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
  20. {
  21.     g_cuurentcmd = cmd;
  22.     switch (cmd) {
  23.         case AUDIO_DRV_PCM_IOCTL_RENDER_START:
  24.         case AUDIO_DRV_PCM_IOCTL_RENDER_RESUME:
  25.             RK809DeviceRegConfig(rk817_render_start_regmap_config);
  26.         break;
  27.        case AUDIO_DRV_PCM_IOCTL_RENDER_STOP:
  28.        case AUDIO_DRV_PCM_IOCTL_RENDER_PAUSE:
  29.            RK809DeviceRegConfig(rk817_render_stop_regmap_config);
  30.            break;
  31.        case AUDIO_DRV_PCM_IOCTL_CAPTURE_START:
  32.        case AUDIO_DRV_PCM_IOCTL_CAPTURE_RESUME:
  33.           RK809DeviceRegConfig(rk817_capture_start_regmap_config);
  34.           break;
  35.        case AUDIO_DRV_PCM_IOCTL_CAPTURE_STOP:
  36.        case AUDIO_DRV_PCM_IOCTL_CAPTURE_PAUSE:
  37.             RK809DeviceRegConfig(rk817_capture_stop_regmap_config);
  38.          break;
  39.        default:
  40.          break;
  41.   }
  42.   return HDF_SUCCESS;
  43. }
复制代码
HdfDriverEntry结构体的具体填充:
  1. /*获取codec service,以及注册codec*/
  2. static int32_t Rk809DriverInit(struct HdfDeviceObject *device)
  3. {
  4.    ......
  5.    CodecGetConfigInfo(device, &(g_chip->codec))
  6.    CodecSetConfigInfo(&(g_chip->codec),  &(g_chip->dai)
  7.    GetServiceName(device)
  8.    CodecGetDaiName(device,  &(g_chip->dai.drvDaiName)
  9.    OsalMutexInit(&g_rk809Data.mutex);
  10.    AudioRegisterCodec(device, &(g_chip->codec), &(g_chip->dai)
  11.    ......
  12. }   
  13. /*将codec service绑定到HDF*/
  14. static int32_t Rk809DriverBind(struct HdfDeviceObject *device)
  15. {
  16.     struct CodecHost *codecHost;
  17.     ......
  18.     codecHost = (struct CodecHost *)OsalMemCalloc(sizeof(*codecHost));
  19.     ......
  20.     codecHost->device = device;
  21.     device->service = &codecHost->service;
  22.    return HDF_SUCCESS;
  23. }
  24. /*释放资源*/
  25. static void RK809DriverRelease(struct HdfDeviceObject *device)
  26. {
  27.    struct CodecHost *codecHost;
  28.    ......
  29.    codecHost = (struct CodecHost *)device->service;
  30.    if (codecHost == NULL) {
  31.        HDF_LOGE("CodecDriverRelease: codecHost is NULL");
  32.        return;
  33.    }
  34.    OsalMemFree(codecHost);
  35. }
复制代码
相干设置如下:
  1. device_codec :: device {
  2.             device0 :: deviceNode {
  3.                 policy = 1;
  4.                 priority = 50;
  5.                 preload = 0;
  6.                 permission = 0666;
  7.                 moduleName = "CODEC_RK809";
  8.                 serviceName = "codec_service_0";
  9.                 deviceMatchAttr = "hdf_codec_driver";
  10.             }
  11. }
复制代码
2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/codec_config.hcs
该文件涉及音量、静音模式、mic、通道模式等相干寄存器设置
DAI驱动开发实例

代码路径:
  1. device/board/kaihong/khdvk_3566b/audio_drivers/codec/dai/
复制代码
  1. .moduleVersion = 1,
  2. .moduleName = "DAI_RK3568",
  3. .Bind = DaiDriverBind,
  4. .Init = DaiDriverInit,
  5. .Release = DaiDriverRelease,
复制代码
g_daiData:dai设备私有设置,其中包含dai设备的初始化、读写寄存器、操作函数。
g_daiDeviceOps:dai设备操作函数集,包含了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. };
复制代码
1> AudioDaiOps结构体的具体填充
  1. /*Rk3568DaiHwParams中主要完成一些pcm流信息的设置*/
  2. int32_t Rk3568DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
  3. {
  4.      ......  
  5.      data->pcmInfo.channels = param->channels;
  6.      if (AudioFormatToBitWidth(param->format, &bitWidth) != HDF_SUCCESS) {
  7.          AUDIO_DEVICE_LOG_ERR("AudioFormatToBitWidth error");
  8.          return HDF_FAILURE;
  9.      }
  10.      data->pcmInfo.bitWidth = bitWidth;
  11.      data->pcmInfo.rate = param->rate;
  12.      data->pcmInfo.streamType = param->streamType;
  13.      i2sTdm = dev_get_drvdata(&platformdev->dev);
  14.      ret = RK3568I2sTdmSetSysClk(i2sTdm, param);
  15.      if (ret != HDF_SUCCESS) {
  16.          AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetSysClk error");
  17.          return HDF_FAILURE;
  18.      }
  19.      ret = RK3568I2sTdmSetMclk(i2sTdm, &mclk, param);
  20.      if (ret != HDF_SUCCESS) {
  21.          AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetMclk error");
  22.          return HDF_FAILURE;
  23.      }
  24.      AUDIO_DEVICE_LOG_DEBUG("success");
  25.      return HDF_SUCCESS;
  26. }
  27. int32_t Rk3568NormalTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
  28. {
  29.     ......
  30.     Rk3568TxAndRxSetReg(i2sTdm, streamType, triggerFlag);
  31.     ......
  32. }
复制代码
2> DaiData结构体的具体填充
  1. /*封装linux内核的读寄存器接口*/
  2. int32_t Rk3568DeviceReadReg(const struct DaiDevice *dai, uint32_t reg, uint32_t *val)
  3. {
  4.     ......
  5.     if (regmap_read(i2sTdm->regmap, reg, val)) {
  6.     ......
  7. }
  8. /*封装linux内核的写寄存器接口*/  
  9. int32_t Rk3568DeviceWriteReg(const struct DaiDevice *dai, uint32_t reg, uint32_t value)
  10. {
  11.     ......
  12.     if (regmap_write(i2sTdm->regmap, reg, value)) {
  13.     ......
  14. }
  15. /*dai 设备的初始化*/
  16. int32_t Rk3568DaiDeviceInit(struct AudioCard *card, const struct DaiDevice *dai)
复制代码
HdfDriverEntry结构体中的bind、init、release具体填充:
  1. static int32_t DaiDriverInit(struct HdfDeviceObject *device)
  2. {
  3.     ......
  4.     DaiGetConfigInfo(device, &g_daiData)
  5.     DaiGetServiceName(device)
  6.     AudioSocRegisterDai(device, (void *)&g_daiData);
  7.     ......
  8. }
  9. static int32_t DaiDriverBind(struct HdfDeviceObject *device)
  10. {
  11.     ......
  12.     daiHost->device = device;
  13.     device->service = &daiHost->service;
  14.     g_daiData.daiInitFlag = false;
  15.     ......
  16. }
  17. static void DaiDriverRelease(struct HdfDeviceObject *device)
  18. {
  19.     ......
  20.     OsalMutexDestroy(&g_daiData.mutex);
  21.     daiHost = (struct DaiHost *)device->service;
  22.     OsalMemFree(daiHost);
  23.     ......
  24. }
复制代码
4.设置dai hcs文件
1> vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs
  1. device_dai0 :: device {
  2.     device0 :: deviceNode {
  3.         policy = 1;
  4.         priority = 50;
  5.         preload = 0;
  6.         permission = 0666;
  7.         moduleName = "DAI_RK3568";
  8.         serviceName = "dai_service";
  9.         deviceMatchAttr = "hdf_dai_driver";
  10.     }
  11. }
复制代码
2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/dai_config.hcs
该文件涉及I2S时序、设置参数以及rk809使能等相干寄存器设置
Platform驱动开发实例

  1. struct HdfDriverEntry g_platformDriverEntry = {
  2. .moduleVersion = 1,
  3. .moduleName = "DMA_RK3568",
  4. .Bind = PlatformDriverBind,
  5. .Init = PlatformDriverInit,
  6. .Release = PlatformDriverRelease,
  7. }; HDF_INIT(g_platformDriverEntry);
复制代码
  1. struct AudioDmaOps g_dmaDeviceOps = {
  2. .DmaBufAlloc = Rk3568DmaBufAlloc, //dma内存申请函数接口
  3. .DmaBufFree = Rk3568DmaBufFree,   // dma内存释放函数接口
  4. .DmaRequestChannel = Rk3568DmaRequestChannel,  // dma申请通道函数接口
  5. .DmaConfigChannel = Rk3568DmaConfigChannel,    // dma通道配置函数接口
  6. .DmaPrep = Rk3568DmaPrep,             // dma准备函数接口
  7. .DmaSubmit = Rk3568DmaSubmit,         // dma submit函数接口
  8. .DmaPending = Rk3568DmaPending,       // dma pending函数接口
  9. .DmaPause = Rk3568DmaPause,           // dma暂停、停止函数接口
  10. .DmaResume = Rk3568DmaResume,         // dma恢复函数接口
  11. .DmaPointer = Rk3568PcmPointer,       // dma获取当前播放或录音位置函数接口
  12. };
复制代码

  1. struct PlatformData g_platformData = {
  2. .PlatformInit = AudioDmaDeviceInit,   // dma设备初始化接口
  3. .ops = &g_dmaDeviceOps,
  4. };
复制代码
HdfDriverEntry结构体中的bind、init、release具体填充:
  1. static int32_t PlatformDriverInit(struct HdfDeviceObject *device)
  2. {
  3.     ......
  4.     PlatformGetServiceName(device);
  5.     AudioSocRegisterPlatform(device, &g_platformData)
  6.     ......
  7. }
  8. static int32_t PlatformDriverBind(struct HdfDeviceObject *device)
  9. {
  10.     ......
  11.     platformHost->device = device;
  12.     device->service = &platformHost->service;
  13.     ......
  14. }
  15. static void PlatformDriverRelease(struct HdfDeviceObject *device)
  16. {
  17.    ......
  18.    platformHost = (struct PlatformHost *)device->service;
  19.    OsalMemFree(platformHost);
  20.    ......
  21. }
复制代码
1> vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs
相干设置如下:
  1. device_dma :: device {
  2.      device0 :: deviceNode {
  3.          policy = 1;
  4.          priority = 50;
  5.          preload = 0;
  6.          permission = 0666;
  7.          moduleName = "DMA_RK3568";
  8.          serviceName = "dma_service_0";
  9.          deviceMatchAttr = "hdf_dma_driver";
  10.      }
  11. }
复制代码
2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/dma_config.hcs
没有特别参数须要设置,一样平常环境下不需改动。
Makefile和Kconfig设置文件
文件路径:
  1. drivers/adapter/khdf/linux/model/audio
复制代码
Makefile文件相干内容:
  1. obj-$(CONFIG_DRIVERS_HDF_AUDIO_RK3566) += \
  2.       $(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_adapter.o \
  3.       $(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_impl.o \
  4.       $(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_linux_driver.o \
  5.       $(KHDF_AUDIO_RK3566_DIR)/dsp/src/rk3568_dsp_adapter.o \
  6.       $(KHDF_AUDIO_RK3566_DIR)/dsp/src/rk3568_dsp_ops.o \
  7.       $(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_adapter.o \
  8.       $(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_ops.o \
  9.       $(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_linux_driver.o \
  10.       $(KHDF_AUDIO_RK3566_DIR)/soc/src/rk3568_dma_adapter.o \
  11.       $(KHDF_AUDIO_RK3566_DIR)/soc/src/rk3568_dma_ops.o
复制代码
Kconfig相干内容:
  1. config DRIVERS_HDF_AUDIO_RK3566
  2.     bool "Enable HDF Audio Codec driver"
  3.     default n
  4.     depends on DRIVERS_HDF_AUDIO
  5.     help
  6.        Answer Y to choice HDF Audio Codec driver.
复制代码
LCD

khdvk_3566b平台默认支持一个mipi接口的lcd屏幕
LCD的适配主要依靠于HDF表现模型,表现驱动模型基于 HDF 驱动框架、Platform 接口及 OSAL 接口开发,可以屏蔽差异内核形态(LiteOS、Linux)差异,适用于差异芯片平台,为表现屏器件提供统一的驱动平台。
如图为 HDF Display驱动模型层次关系

当前驱动模型主要部署在内核态中,向上对接到 Display 公共 hal 层,辅助 HDI 的实现。表现驱动通过 Display-HDI 层对图形服务暴露表现屏驱动本领;向下对接表现屏 panel 器件,驱动屏幕正常工作,自上而下买通表现全流程通路。
所以LCD的适配主要在于LCD panel器件驱动的适配
器件驱动的适配分为2部分:panel驱动和hcs设置
涉及的文件有:
  1. drivers/framework/model/display/driver/panel
  2. vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info
  3. vendor/kaihong/khdvk_3566b/hdf_config/khdf/input
复制代码
panel驱动

器件驱动主要围绕如下接口睁开:
  1. struct PanelData {
  2.     struct HdfDeviceObject *object;
  3.     int32_t (*init)(struct PanelData *panel);
  4.     int32_t (*on)(struct PanelData *panel);
  5.     int32_t (*off)(struct PanelData *panel);
  6.     int32_t (*prepare)(struct PanelData *panel);
  7.     int32_t (*unprepare)(struct PanelData *panel);
  8.     struct PanelInfo *info;
  9.     enum PowerStatus powerStatus;
  10.     struct PanelEsd *esd;
  11.     struct BacklightDev *blDev;
  12.     void *priv;
  13. };
复制代码
驱动中在初始化接口中实例化该结构体:
  1. panelSimpleDev->panel.init = PanelSimpleInit;
  2. panelSimpleDev->panel.on = PanelSimpleOn;
  3. panelSimpleDev->panel.off = PanelSimpleOff;
  4. panelSimpleDev->panel.prepare = PanelSimplePrepare;
  5. panelSimpleDev->panel.unprepare = PanelSimpleUnprepare;
  6. static void PanelResInit(struct panel_jdi_gt911_dev *panel_dev)
  7. {
  8.    ......   
  9.    panel_dev->panel.info = &g_panelInfo;
  10.    panel_dev->panel.init = PanelInit;
  11.    panel_dev->panel.on = PanelOn;
  12.    panel_dev->panel.off = PanelOff;
  13.    panel_dev->panel.prepare = PanelPrepare;
  14.    panel_dev->panel.unprepare = PanelUnprepare;
  15.    ......
  16. }
复制代码
g_panelInfo设置panel基础参数
PanelInit负责panel的软件初始化
PanelOn负责亮屏
PanelOff负责灭屏
PanelPrepare负责亮屏的硬件时序初始化
PanelUnprepare负责灭屏的硬件时序初始化
实例化后利用RegisterPanel接口向display模型注册该panel驱动即可
须要说明的是,khdvk_3566b上的这款lcd利用的时候DRM表现框架
hcs设置

  1. device3 :: deviceNode {
  2.        policy = 0;
  3.        priority = 100;
  4.        preload = 0;
  5.        moduleName = "LCD_MIPI_JDI_GT911";
  6. }
复制代码
背光

背光控制分为原生linux内核框架下背光驱动以及基于HDF框架开发的背光驱动模型。
rk3566背光是通过pwm控制占空比实现的,具体利用的是pwm4
linux背光驱动代码路径:
  1. linux-5.10/drivers/video/backlight/pwm_bl.c
  2. linux-5.10/drivers/video/backlight/backlight.c
  3. linux-5.10/drivers/pwm/pwm-rockchip.c
复制代码
利用HDF框架下的背光驱动,须要关闭原生驱动
  1.     # CONFIG_BACKLIGHT_PWM is not set
复制代码
HDF实现

基于HDF框架开发的背光驱动模型,如下图:

代码路径:
  1. drivers/framework/model/display/driver/backlight/hdf_bl.c
复制代码
HDF BL入口函数:
  1.     static int32_t BacklightInit(struct HdfDeviceObject *object)
  2.     {
  3.          if (object == NULL) {
  4.          HDF_LOGE("%s: object is null!", __func__);
  5.          return HDF_FAILURE;
  6.          }
  7.    
  8.          HDF_LOGI("%s success", __func__);
  9.          return HDF_SUCCESS;
  10.     }
  11.    
  12.     struct HdfDriverEntry g_blDevEntry = {
  13.         .moduleVersion = 1,
  14.         .moduleName = "HDF_BL",
  15.         .Init = BacklightInit,
  16.         .Bind = BacklightBind,
  17.     };
  18.    
  19.     HDF_INIT(g_blDevEntry);
复制代码
代码路径:
  1. drivers/framework/model/display/driver/backlight/pwm_bl.c
复制代码
HDF PWM入口函数:
  1.     struct HdfDriverEntry g_pwmBlDevEntry = {
  2.     .moduleVersion = 1,
  3.     .moduleName = "PWM_BL",
  4.     .Init = BlPwmEntryInit,
  5.     };
  6.     HDF_INIT(g_pwmBlDevEntry);
复制代码
具体控制背光的接口:
  1.     static int32_t BlPwmUpdateBrightness(struct BacklightDev *blDev, uint32_t brightness)
  2.     {
  3.         int32_t ret;
  4.         uint32_t duty;
  5.         struct BlPwmDev *blPwmDev = NULL;
  6.    
  7.         blPwmDev = ToBlDevPriv(blDev);
  8.         if (blPwmDev == NULL) {
  9.             HDF_LOGE("%s blPwmDev is null", __func__);
  10.             return HDF_FAILURE;
  11.         }
  12.    
  13.         if (blPwmDev->props.maxBrightness == 0) {
  14.             HDF_LOGE("%s maxBrightness is 0", __func__);
  15.             return HDF_FAILURE;
  16.         }
  17.    
  18.         if (brightness == 0) {
  19.              return PwmDisable(blPwmDev->pwmHandle);
  20.         }
  21.    
  22.         duty = (brightness * blPwmDev->config.period) / blPwmDev->props.maxBrightness;
  23.         ret = PwmSetDuty(blPwmDev->pwmHandle, duty);
  24.         if (ret != HDF_SUCCESS) {
  25.             HDF_LOGE("%s: PwmSetDuty failed, ret %d", __func__, ret);
  26.             return HDF_FAILURE;
  27.         }
  28.         return PwmEnable(blPwmDev->pwmHandle);
  29.     }
  30.    
  31.     static struct BacklightOps g_blDevOps = {
  32.          .updateBrightness = BlPwmUpdateBrightness,
  33.     };
复制代码
HDF PWM实现的调用的就是内核pwm的接口。

代码路径:
  1. drivers/framework/model/display/driver/panel/mipi_jdi_gt911.c
复制代码
在LCD HDF器件驱动注册背光:
  1.     panel_dev->panel.blDev = GetBacklightDev("hdf_pwm");
  2.     if (panel_dev->panel.blDev == NULL) {
  3.         HDF_LOGE("%s GetBacklightDev fail", __func__);
  4.         goto FAIL;
  5.     }
复制代码
HCS设置

驱动hcs设置:
  1.     device_pwm_bl :: device {
  2.         device0 :: deviceNode {
  3.             policy = 0;
  4.             priority = 95;
  5.             preload = 0;
  6.             moduleName = "PWM_BL";
  7.             deviceMatchAttr = "pwm_bl_dev";
  8.         }
  9.     }
  10.     device_backlight :: device {
  11.         device0 :: deviceNode {
  12.             policy = 2;
  13.             priority = 90;
  14.             preload = 0;
  15.             permission = 0660;
  16.             moduleName = "HDF_BL";
  17.             serviceName = "hdf_bl";
  18.         }
  19.     }
复制代码
pwm背光的hcs设置:
  1.     root {
  2.         backlightConfig {
  3.             pwmBacklightConfig {
  4.                 match_attr = "pwm_bl_dev";
  5.                 pwmDevNum = 1;
  6.                 pwmMaxPeroid = 25000;
  7.                 backlightDevName = "hdf_pwm";
  8.                 minBrightness = 0;
  9.                 defBrightness = 127;
  10.                 maxBrightness = 255;
  11.            }
  12.        }
  13.     }
复制代码
测试

cat /sys/kernel/debug/pwm 来查看hdf pwm是否申请到pwm4
申请成功有如下效果:
requested 代表申请成功
enabled 代表pwm4使能成功
  1.     # cat /sys/kernel/debug/pwm
  2.     platform/fe6e0000.pwm, 1 PWM device
  3.     pwm-0   (backlight           ): requested period: 25000 ns duty: 0 ns polarity: normal
复制代码
表现适配

表现适配须要完成的工作:图形服务HDI接口适配、GPU适配、mipi dsi驱动适配
表现HDI

表现HDI 对图形服务提供表现驱动本领,包括表现图层的管理、表现内存的管理及硬件加速等。 表现HDI须要适配两部分:gralloc 和 display_device。
OpenHarmony提供了利用与Hi3516DV300参考实现,厂商可根据实际环境参考适配,khdvk_3566b display适配是在//device/soc/rockchip/hardware/display目录下,仓名为 device_soc_rockchip 。
display gralloc适配

gralloc模块提供表现内存管理功能,该实现基于drm开发。
drm设备节点界说在//device/soc/rockchip/hardware/display/src/display_gralloc/display_gralloc_gbm.c文件中,根据khdvk_3566b实际环境修改了drm文件节点。
  1. const char *g_drmFileNode = "/dev/dri/renderD128";
复制代码
display device适配

display device模块提供表现设备管理、layer管理、硬件加速等功能。
  1. //device/soc/rockchip/hardware/display/src/display_device/drm/drm_device.cpp
  2. std::shared_ptr<HdiDeviceInterface> DrmDevice::Create()
  3. {
  4.     DISPLAY_DEBUGLOG();
  5.     if (mDrmFd == nullptr) {
  6.         const std::string name("rockchip");    // 将drm驱动设备名称修改为“rockchip”
  7.         int drmFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);  // 将drm驱动设备文件句柄修改为"/dev/dri/card0"
  8.         if (drmFd < 0) {
  9.             DISPLAY_LOGE("drm file:%{public}s open failed %{public}s", name.c_str(), strerror(errno));
  10.             return nullptr;
  11.         }
  12.         DISPLAY_DEBUGLOG("the drm fd is %{public}d", drmFd);
  13.         mDrmFd = std::make_shared<HdiFd>(drmFd);
  14.     }
  15.     if (mInstance == nullptr) {
  16.         mInstance = std::make_shared<DrmDevice>();
  17.     }
  18.     return mInstance;
  19. }
复制代码
  1. //device/soc/rockchip/hardware/display/src/display_gfx/display_gfx.c
复制代码
硬件合成文件添加了颜色空间的支持模式
  1. RgaSURF_FORMAT colorSpaceModeChange(PixelFormat color, uint8_t *isYuv)
  2. {
  3.     RgaSURF_FORMAT rkFormat;
  4.     switch (color) {
  5.         case PIXEL_FMT_RGB_565:          /**< RGB565 format */
  6.             rkFormat = RK_FORMAT_RGB_565;
  7.             *isYuv = 0;
  8.             break;
  9.         case PIXEL_FMT_RGBA_4444:        /**< RGBA4444 format */
  10.             rkFormat = RK_FORMAT_RGBA_4444;
  11.             *isYuv = 0;
  12.             break;
  13.         case PIXEL_FMT_RGBA_5551:        /**< RGBA5551 format */
  14.             rkFormat = RK_FORMAT_RGBA_5551;
  15.             *isYuv = 0;
  16.             break;
  17.         case PIXEL_FMT_RGBX_8888:        /**< RGBX8888 format */
  18.             rkFormat = RK_FORMAT_RGBX_8888;
  19.             *isYuv = 0;
  20.             break;
  21.         case PIXEL_FMT_RGBA_8888:        /**< RGBA8888 format */
  22.             rkFormat = RK_FORMAT_RGBA_8888;
  23.             *isYuv = 0;
  24.             break;
  25.         case PIXEL_FMT_RGB_888:          /**< RGB888 format */
  26.             rkFormat = RK_FORMAT_RGB_888;
  27.             *isYuv = 0;
  28.             break;
  29.         case PIXEL_FMT_BGR_565:          /**< BGR565 format */
  30.             rkFormat = RK_FORMAT_BGR_565;
  31.             *isYuv = 0;
  32.             break;
  33.         case PIXEL_FMT_BGRA_4444:        /**< BGRA4444 format */
  34.             rkFormat = RK_FORMAT_BGRA_4444;
  35.             *isYuv = 0;
  36.             break;
  37.         case PIXEL_FMT_BGRA_5551:        /**< BGRA5551 format */
  38.             rkFormat = RK_FORMAT_BGRA_5551;
  39.             *isYuv = 0;
  40.             break;
  41.         case PIXEL_FMT_BGRX_8888:        /**< BGRX8888 format */
  42.             rkFormat = RK_FORMAT_BGRX_8888;
  43.             *isYuv = 0;
  44.             break;
  45.         case PIXEL_FMT_BGRA_8888:        /**< BGRA8888 format */
  46.             rkFormat = RK_FORMAT_BGRA_8888;
  47.             *isYuv = 0;
  48.             break;
  49.         case PIXEL_FMT_YCBCR_422_SP:     /**< YCBCR422 semi-planar format */
  50.             rkFormat = RK_FORMAT_YCbCr_420_SP;
  51.             *isYuv = 1;
  52.             break;
  53.         case PIXEL_FMT_YCRCB_422_SP:     /**< YCRCB422 semi-planar format */
  54.             rkFormat = RK_FORMAT_YCrCb_422_SP;
  55.             *isYuv = 1;
  56.             break;
  57.         case PIXEL_FMT_YCBCR_420_SP:     /**< YCBCR420 semi-planar format */
  58.             rkFormat = RK_FORMAT_YCbCr_420_SP;
  59.             *isYuv = 1;
  60.             break;
  61.         case PIXEL_FMT_YCRCB_420_SP:     /**< YCRCB420 semi-planar format */
  62.             rkFormat = RK_FORMAT_YCrCb_420_SP;
  63.             *isYuv = 1;
  64.             break;
  65.         case PIXEL_FMT_YCBCR_422_P:      /**< YCBCR422 planar format */
  66.             rkFormat = RK_FORMAT_YCbCr_422_P;
  67.             *isYuv = 1;
  68.             break;
  69.         case PIXEL_FMT_YCRCB_422_P:      /**< YCRCB422 planar format */
  70.             rkFormat = RK_FORMAT_YCrCb_422_P;
  71.             *isYuv = 1;
  72.             break;
  73.         case PIXEL_FMT_YCBCR_420_P:      /**< YCBCR420 planar format */
  74.             rkFormat = RK_FORMAT_YCbCr_420_P;
  75.             *isYuv = 1;
  76.             break;
  77.         case PIXEL_FMT_YCRCB_420_P:      /**< YCRCB420 planar format */
  78.             rkFormat = RK_FORMAT_YCrCb_420_P;
  79.             *isYuv = 1;
  80.             break;
  81.         case PIXEL_FMT_YUYV_422_PKG:     /**< YUYV422 packed format */
  82.             rkFormat = RK_FORMAT_YUYV_422;
  83.             *isYuv = 1;
  84.             break;
  85.         case PIXEL_FMT_UYVY_422_PKG:     /**< UYVY422 packed format */
  86.             rkFormat = RK_FORMAT_UYVY_422;
  87.             *isYuv = 1;
  88.             break;
  89.         case PIXEL_FMT_YVYU_422_PKG:     /**< YVYU422 packed format */
  90.             rkFormat = RK_FORMAT_YUYV_422;
  91.             *isYuv = 1;
  92.             break;
  93.         case PIXEL_FMT_VYUY_422_PKG:     /**< VYUY422 packed format */
  94.             rkFormat = RK_FORMAT_VYUY_422;
  95.             *isYuv = 1;
  96.             break;
  97.         default:
  98.             rkFormat = RK_FORMAT_UNKNOWN;
  99.             break;
  100.     }
  101.     return rkFormat;
  102. }
复制代码
在合成时增加了旋转90、180、270度
  1. int32_t TransformTypeChange(TransformType type)
  2. {
  3.     int32_t rkRotateType;
  4.     switch (type) {
  5.         case ROTATE_90:            /**< Rotation by 90 degrees */
  6.             rkRotateType = IM_HAL_TRANSFORM_ROT_90;
  7.             break;
  8.         case ROTATE_180:             /**< Rotation by 180 degrees */
  9.             rkRotateType = IM_HAL_TRANSFORM_ROT_180;
  10.             break;
  11.         case ROTATE_270:             /**< Rotation by 270 degrees */
  12.             rkRotateType = IM_HAL_TRANSFORM_ROT_270;
  13.             break;
  14.         default:
  15.             rkRotateType = 0;        /**< No rotation */
  16.             break;
  17.     }
  18.     return rkRotateType;
  19. }
复制代码
测试验证

hello_composer 测试模块:Rosen图形框架提供的测试程序,主要表现流程,HDI接口等功能是否正常,默认随系统编译。
代码路径:
  1. foundation/graphic/graphic_2d/rosen/samples/composer/
  2. ├── BUILD.gn
  3. ├── hello_composer.cpp
  4. ├── hello_composer.h
  5. ├── layer_context.cpp
  6. ├── layer_context.h
  7. └── main.cpp
复制代码
具体验证如下:
  1.    service_control stop render_service
复制代码
  1.    service_control stop fondation
复制代码
  1.    #cd /system/bin
  2.    #./hello_composer
  3.    rga_api version 1.3.0_[1] (df26244 build: 2021-09-01 11:23:31 base: )
复制代码
查看mipi表现屏幕上的变革
https://gitee.com/openharmony/drivers_peripheral/tree/master/display/test/unittest/standard单位测试:HDI表现模块提供的测试模块,主要测试HDI接口、表现buffer、驱动等本领,测试时也须要关闭render service和fondation进程。
代码路径:/drivers/peripheral/display/test/unittest/standard
  1. ├── BUILD.gn
  2. ├── common
  3. │   ├── display_test.h
  4. │   ├── display_test_utils.cpp
  5. │   └── display_test_utils.h
  6. ├── display_device
  7. │   ├── hdi_composition_check.cpp
  8. │   ├── hdi_composition_check.h
  9. │   ├── hdi_device_test.cpp
  10. │   ├── hdi_device_test.h
  11. │   ├── hdi_test_device_common.h
  12. │   ├── hdi_test_device.cpp
  13. │   ├── hdi_test_device.h
  14. │   ├── hdi_test_display.cpp
  15. │   ├── hdi_test_display.h
  16. │   ├── hdi_test_layer.cpp
  17. │   ├── hdi_test_layer.h
  18. │   ├── hdi_test_render_utils.cpp
  19. │   └── hdi_test_render_utils.h
  20. │── display_gfx
  21. │   │── display_gfx_test.cpp
  22. │   │── display_gfx_test.h
  23. │   │── soft_blit.cpp
  24. │   │── soft_blit.h
  25. └── display_gralloc
  26.     ├── display_gralloc_test.cpp
  27.     └── display_gralloc_test.h
复制代码
具体验证如下:
  1.   group("hdf_test_display") {
  2.     testonly = true
  3.     deps = [
  4.     "fuzztest:hdf_display_fuzztest",
  5.     "unittest/standard:hdf_unittest_display",        //添加display单元测试
  6.     ]
  7.   }
复制代码
  1. ohos_unittest("gralloctest") {
  2.   module_out_path = module_output_path
  3.   sources = [ "display_gralloc/display_gralloc_test.cpp" ]
  4.   deps = [
  5.     "//drivers/peripheral/display/hal:hdi_display_gralloc",
  6.     "//third_party/googletest:gtest_main",
  7.   ]
  8.   include_dirs = [
  9.     "common",
  10.     "//drivers/peripheral/display/hal/default_standard/include",
  11.     "//drivers/peripheral/display/hal/default_standard/src/display_gralloc",
  12.     "//device/soc/rockchip/hardware/display/src/display_gralloc",        //添加这行,将display_gralloc包含进编译
  13.     "//drivers/peripheral/display/interfaces/include",
  14.     "//drivers/peripheral/base",
  15.     "//drivers/peripheral/display/interfaces/include",
  16.     "//foundation/graphic/standard/utils/include",
  17.   ]
  18.   external_deps = [
  19.     "device_driver_framework:libhdf_utils",
  20.     "utils_base:utils",
  21.   ]
  22. }
复制代码
  1.    ./build.sh --product-name khdvk_3566b --build-target hdf_test_display
复制代码
  1. hdc_std.exe file send D:\hdc\devicetest /system/bin/
  2. hdc_std.exe file send D:\hdc\gfxtest /system/bin/
  3. hdc_std.exe file send D:\hdc\gralloctest /system/bin/
复制代码
进入hdc下令hdc_std.exe shell后
先关闭render service和foundation:
  1. service_control stop render_service
  2. service_control stop fondation
复制代码
再分别执行下令,查看mipi屏表现效果:
  1. cd /system/bin/
复制代码
执行devicetest
  1. chmod -R 777 devicetest
  2. devicetest
复制代码
执行gfxtest
  1. chmod -R 777 gfxtest
  2. gfxtest
复制代码
执行gralloctest
  1. chmod -R 777 gralloctest
  2. gralloctest
复制代码
GPU

GPU图形处理器, khdvk_3566b GPU适配是在//device/soc/rockchip/hardware/gpu目录下,目前采用的是rockchip提供闭源的bifrost gpu方案。
目录结构:
  1. ├── BUILD.gn
  2. ├── lib64
  3. │   └── libmali-bifrost-g52-g2p0-ohos.so
  4. ├── lib
  5. │   └── libmali-bifrost-g52-g2p0-ohos.so
  6. └── include
  7.     └── gbm.h
复制代码
gpu编译的内容,我们来看下BUILD.gn的内容,其中我们预编译了libmali-bifrost-g52-g2p0-ohos.so动态库,khdvk_3566b是arm64位的,所以编译了lib64目录下的libmali-bifrost-g52-g2p0-ohos.so动态库。其中gup模块符号链接libEGL.so、libGLESv1.so、libGLESv2.so、libGLESv3.so、libmali.so.0、libmali.so.1动态库的符号。
  1. import("//build/ohos.gni")
  2. import("//build/ohos/ndk/ndk.gni")
  3. config("libmali-bifrost-g52-g2p0-ohos") {
  4.   include_dirs = [ "include" ]
  5.   cflags = [
  6.     "-Wno-incompatible-pointer-types",
  7.     "-Werror",
  8.     "-Wimplicit-function-declaration",
  9.     "-Wno-error=unused-variable",
  10.   ]
  11.   cflags = []
  12. }
  13. ohos_prebuilt_shared_library("mali-bifrost-g52-g2p0-ohos") {
  14.   if (target_cpu == "arm") {
  15.     source = "lib/libmali-bifrost-g52-g2p0-ohos.so"
  16.   } else if (target_cpu == "arm64") {
  17.     source = "lib64/libmali-bifrost-g52-g2p0-ohos.so"
  18.   }
  19.   # decoupling system.img and vendor.img
  20.   install_images = [ chipset_base_dir ]
  21.   relative_install_dir = "chipsetsdk"
  22.   subsystem_name = "rockchip_products"
  23.   part_name = "rockchip_products"
  24.   install_enable = true
  25.   symlink_target_name = [
  26.     "libEGL.so",
  27.     "libGLESv1.so",
  28.     "libGLESv2.so",
  29.     "libGLESv3.so",
  30.     "libmali.so.0",
  31.     "libmali.so.1",
  32.   ]
  33. }
复制代码
TOUCH PANEL

常见的INPUT设备有键盘、鼠标、游戏杆、Touch Screen等。Touch 设备与主机通讯采用标准 I2C 总线,触屏 IC 提供停止支持,进步了触屏数据的实时性。本项目的触摸屏器件IC 为 GT911。
驱动框架模型

INPUT驱动模型


INPUT 驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。
(1)设备管理层:为各类输入设备驱动提供input设备的注册、注销接口,同时统一管理 input 设备列表;
(2)平台驱动层:指各类input设备的公共抽象驱动(比方触摸屏的公共驱动),负责对板级硬件进行初始化、硬件停止处理、向manager注册input设备等;
(3)器件驱动层:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。
HDI接口层框架图

INPUT驱动提供给系统服务Input Service可直接调用的驱动本领接口,按照属性分类三类:input设备管理模块、input数据上报模块、input业务控制模块,HDI接口主要包括如下三大类:


HDF驱动适配

HCS设置

设置设备形貌信息,在device_info.hcs中添加device_touch_chip:
  1. input :: host {
  2.             hostName = "input_host";
  3.             priority = 100;
  4.             device_input_manager :: device {   // Input管理层设备描述信息
  5.                 device0 :: deviceNode {
  6.                     policy = 2;
  7.                     priority = 100;
  8.                     preload = 0;
  9.                     permission = 0660;
  10.                     moduleName = "HDF_INPUT_MANAGER";
  11.                     serviceName = "hdf_input_host";
  12.                     deviceMatchAttr = "";
  13.                 }
  14.             }
  15.             device_hdf_touch :: device {      // Input公共驱动层设备描述信息
  16.                 device0 :: deviceNode {
  17.                     policy = 2;
  18.                     priority = 120;
  19.                     preload = 0;
  20.                     permission = 0660;
  21.                     moduleName = "HDF_TOUCH";
  22.                     serviceName = "hdf_input_event1";
  23.                     deviceMatchAttr = "touch_device1";
  24.                 }
  25.             }
  26.             device_touch_chip :: device {     // Input器件驱动层信息
  27.                 device0 :: deviceNode {
  28.                     policy = 0;
  29.                     priority = 130;
  30.                     preload = 0;
  31.                     permission = 0660;
  32.                     moduleName = "HDF_TOUCH_GT911";
  33.                     serviceName = "hdf_touch_gt911_service";
  34.                     deviceMatchAttr = "zsj_gt911_5p5";
  35.                 }
  36.             }
  37.             device_hdf_hid :: device {
  38.                 device0 :: deviceNode {
  39.                     policy = 2;
  40.                     priority = 200;
  41.                     preload = 0;
  42.                     permission = 0660;
  43.                     moduleName = "HDF_HID";
  44.                 }
  45.             }
  46.         }
复制代码
设置Touch器件信息,在input_config.hcs中添加器件的特性:
  1. chipConfig {
  2.                     template touchChip {
  3.                         match_attr = "";
  4.                         chipName = "gt911";
  5.                         vendorName = "zsj";
  6.                         chipInfo = "AAAA11222";  
  7.                         busType = 0;
  8.                         deviceAddr = 0x5D;                       
  9.                         irqFlag = 2;
  10.                         maxSpeed = 400;
  11.                         chipVersion = 0; //parse Coord TypeA
  12.                         powerSequence {
  13.                             /* [type, status, dir , delay]
  14.                                 <type> 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:int
  15.                                 <status> 0:off or low  1:on or high  2:no ops
  16.                                 <dir> 0:input  1:output  2:no ops
  17.                                 <delay> meanings delay xms, 20: delay 20ms
  18.                              */
  19.                             powerOnSeq = [4, 0, 1, 5,
  20.                                          3, 0, 1, 10,
  21.                                          3, 1, 1, 60,
  22.                                          4, 2, 0, 50];
  23.                             suspendSeq = [3, 0, 2, 10];
  24.                             resumeSeq = [3, 1, 2, 10];
  25.                             powerOffSeq = [3, 0, 2, 10,
  26.                                            1, 0, 2, 20];
  27.                         }
  28.                     }
  29.                     chip0 :: touchChip {
  30.                         match_attr = "zsj_gt911_5p5";
  31.                         chipInfo = "ZIDN45100";  
  32.                         chipVersion = 0;
  33.                     }     
  34.                 }
复制代码
适配文件

Touch驱动适配涉及的文件及目录:
1、 编辑 Makefile 文件:./drivers/adapter/khdf/linux/model/input/Makefile
2、 公共设置文件:./vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs
3、 私有设置文件:./vendor/kaihong/khdvk_3566b/hdf_config/khdf/input/input_config.hcs
4、 驱动:drivers\framework\model\input\driver\touchscreen
HDF驱动模型高度抽象集成,TP驱动的适配主要是器件驱动层的适配,首先须要明确TP所须要的软硬件资源。
TP模组须要主机上的如下硬件资源:
1.停止引脚
2.Reset引脚
3.利用的哪一组i2c,从设备的地址是什么
4.TP的初始化固件(通常由IC厂商提供)
5.触摸屏的分辨率
TP模组须要依靠主机上的如下软件资源:
1.Hdf gpio子系统 用于设置gpio pin脚以及一些停止资源
2.Hdf i2c 子系统 用于进行i2c通讯
3.Input模型
器件差异化接口适配,示例代码路径:
  1. ./drivers/framework/model/input/driver/touchscreen/Touch_gdi_gt911.c
  2. static struct TouchChipOps g_gt911ChipOps = {     // 器件IC接口
  3.     .Init = ChipInit,                             // 初始化
  4.     .Detect = ChipDetect,                         // 器件检测
  5.     .Resume = ChipResume,                         // 唤醒
  6.     .Suspend = ChipSuspend,                       // 休眠
  7.     .DataHandle = ChipDataHandle,                 // 器件数据读取
  8.     .UpdateFirmware = UpdateFirmware,             // 固件升级
  9.     .SetAbility = SetAbility,                     // 配置
  10. };
复制代码
器件驱动初始化及HDF注册,示例代码路径:
  1. ./drivers/framework/model/input/driver/touchscreen/touch_jdi_gt911.c
  2. static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
  3. {
  4.     ...
  5.     /* 器件配置结构体内存申请、配置信息解析及挂载 */
  6.     chipCfg = ChipConfigInstance(device);
  7.     ...
  8.     /* 器件实例化 */
  9.     chipDev = ChipDeviceInstance();
  10.     ...
  11.     /* 器件信息挂载及器件私有操作挂载 */
  12.     chipDev->chipCfg = chipCfg;
  13.     chipDev->ops = &g_gt911ChipOps;
  14.     ...
  15.     /* 注册器件驱动至平台驱动 */
  16.     RegisterChipDevice(chipDev);
  17.     ...
  18. }
  19. struct HdfDriverEntry g_touchGoodixChipEntry = {
  20.     .moduleVersion = 1,
  21.     .moduleName = "HDF_TOUCH_GT911",
  22.     .Init = HdfGoodixChipInit,          // 器件驱动初始化函数
  23.     .Release = HdfGoodixChipRelease,
  24. };
  25. HDF_INIT(g_touchGoodixChipEntry);       // 注册器件驱动至HDF框架
复制代码
代码分布

  1. /drivers/peripheral/input
  2. /drivers/framework/model/input
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4