HDF Display驱动模型的整体架构加载及运行流程

display 驱动概述
随着电子产业迅速发展,带屏类的设备种类日益增多,各种各样的显示屏也随之出现。
最常见的显示屏有 lcd(liquid crystal display)屏、led(organiclight-emitting diode)点阵屏、oled(organic light-emittingdiode)屏等,根据其各自特点,用于不同的显示场景。显示屏的硬件接口主要有 mipi、hdmi、spi、i2c、rgb、mcu 等,现在用于手机的高分辨率显示屏,主要用的是 mipi 接口,hdmi 接口主要用于显示器或 tv,rgb 和 mcu 接口为并口,主要用于功能机之上。
以 lcd 为例,其驱动主要完成三部分工作:
1、对 lcd driver ic 及模组相关的硬件资源进行初始化,包括配置 mipi 参数,操作 gpio 管脚,设置上下电时序,下发屏端初始化参数序列等;
2、器件驱动操作接口对注册或者对接到标准的显示框架上,例如 drm 架构或者 fb 显示架构,保证在设备亮灭屏状态切换时,显示架构可以通过 panel 驱动注册的接口操控 lcd;
3、背光参数配置及等级设置等。
display驱动模型介绍
驱动模型背景
当前操作系统和 soc 种类繁多,各厂商的显示屏器件也各有不同,随之针对器件的驱动代码也不尽相同,往往是某一款器件驱动,只适用于某单一内核系统或 soc,如果要迁移到其他内核或者 soc,可能会有不小的移植工作量。而且,不同驱动 ic 的驱动代码差异较大,产品更换驱动 ic,则又需要重新开发对应的器件驱动,造成重复工作。因此,我们尝试基于 hdf 驱动框架,编写一套较通用的 display 器件驱动模型,尽可能降低驱动开发者的开发或移植工作量,简化器件驱动开发,提升开发效率。
图1 hdf display驱动模型层次关系
以显示模块为例,上层为图形服务;中间层为 hdi 层(hardware display interface),对图形服务提供驱动能力接口,方便其操作具体的外设器件;显示驱动模型当前部署在内核态,向上对接到 display hdi 的实现,同时在内核对接到标准的显示框架上(如drm、fb);向下对接不同的 panel 驱动,从而自上而下打通显示通路,驱动屏幕点亮。
驱动模型通过逐步兼容不同的显示框架(drm、fb)及差异化的 soc,开发者可基于其快速开发显示屏器件驱动。
驱动模型解析
显示驱动模型基于 hdf 驱动框架、platform 接口及 osal 接口开发,可以屏蔽不同内核形态(liteos、linux)差异,适用于不同芯片平台(hi35xx、hi38xx、v3s等),为显示屏器件提供统一的驱动平台。
当前驱动模型主要部署在内核态中,向上对接到 display 公共 hal 层,辅助 hdi 的实现。显示驱动通过 display-hdi 层对图形服务暴露显示屏驱动能力;向下对接显示屏 panel 器件,驱动屏幕正常工作,自上而下打通显示全流程通路。
模型各层设计说明
display 驱动模型基于 hdf 驱动框架、platform 接口及 osal 接口开发,可以做到不区分os(liteos、linux)和芯片平台(hi35xx、hi38xx、v3s等),为 lcd 器件提供统一的驱动模型。
如图 2 所示,当前 hdf display 驱动模型主要分为四层:标准架构适配层(drm panel adapter driver)、显示公共驱动层(displaycommon driver)、芯片平台适配层(soc adapter driver)、器件驱动层(display panel driver)。
1、标准架构适配层
图3. 标准架构适配层组件
如图 3 所示,本层主要完成对接标准的显示驱动架构,如 drm(direct rending manager)或 fb(framebuffer),以 drm 为例,将 panel 侧驱动接口对接到标准框架中,保证在 drm 框架中实现对 panel 驱动的操作接口,当前注册的接口如下。
static struct drm_panel_funcs g_hdfdrmpanelfuncs = { .get_modes = hdfdrmpanelgetmodes, .enable = hdfdrmpanelenable, .disable = hdfdrmpaneldisable, .prepare = hdfdrmpanelprepare, .unprepare = hdfdrmpanelunprepare,};
2、显示公共驱动层
图4. 显示公共驱动层组件
如图 4 所示,此部分属于整个驱动模型的中枢,所有的屏端接口注册、panel 信息管理、屏幕状态控制、用户态 hdi 接口命令处理、以及通用的基础显示特性,目前都是通过这部分实现。
在本层通过结构体 dispmanager 管理所有的显示信息,其成员 panelmanager 用于记录与显示屏相关的接口及参数信息。同时接收并处理 hdi 层直接对 panel 操作相关的指令(主要用于 l0-l1 等轻量级系统),如 panel 器件信息的获取、休眠唤醒、背光设置等指令。此外,本层还负责实现一些基础显示特性的业务框架,如 esd 检查机制,力求将显示相关的共有逻辑集中到本层实现,以简化 panel 器件驱动的实现,避免 panel 驱动中相同功能的重复实现,便于统一管理和维护。
3、芯片平台适配层
图5. 芯片平台适配层组件
如图 5 所示,借助此 soc 适配层,实现 display 器件驱动和 soc 侧硬件资源的解耦,主要完成芯片平台强相关的参数配置,如 mipi 速率计算及设置、管脚复用配置,以及其他和 soc 强相关的差异化配置及初始化等。
4、器件驱动层
图6. 器件驱动层组件
如图 6 所示,器件驱动层主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、休眠唤醒流程、背光设置、esd 检测等,同时完成 panel 信息的解析,并将 panel 向上注册到公共驱动层进行管理。
基于 display 驱动模型开发 lcd 器件驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发难度和周期,提升开发效率。
说明
以上驱动模型中的各层,需要根据产品自身情况来选择,其中“显示公共驱动层”和“器件驱动层”为必选项,“标准架构适配层”和“芯片平台适配层”则为可选项。对于l0-l1这种轻量级soc,一般都会有与soc强相关的硬件配置需要在“芯片平台适配层”中完成,而对于l2及其以上的soc,通常都会采用标准的显示框架,此时“标准架构适配层”则必不可少。
驱动加载及运行
hdf 的驱动的加载方式,在之前的 hdf 框架介绍章节中已经做过说明,框架通过解析设备描述的 hcs 配置文件,获取到各设备的配置信息,根据 modulename 来匹配对应设备的驱动文件入口,按照配置的加载优先级,依次加载驱动,详细说明会在下一节的“具体开发步骤”中进行描述。
如图 7 所示,简要概括了驱动模型的加载及运行流程,对模型内部组件及关联组件之间的关系做了划分,整体加载流程分为 9 步,分别说明如下:
“显示公共驱动层”和“器件驱动层”为必选项,“标准架构适配层”和“芯片平台适配层”
1、hdf device manager 解析设备描述;
2、hdf 优先加载器件驱动层,构建 panel 设备;
3、将 panel 信息及操作接口注册到公共驱动层;
4、hdf 其次加载芯片平台适配层,进行 soc 相关硬件资源初始化;
5、hdf 再次加载公共驱动层,对共有特性进行初始化;
6、hdf 最后加载标准架构适配层;
7、从公共驱动层中获取到 panelmanager,;
8、将对应 panel 注册到 drm 框架中;
9、在系统运行起来后,drm 会调用 panel ops 进行显示屏控制。
对于采用像 liteos 这种轻量内核的系统,并不会像 linux 内核那样提供标准的显示框架,驱动模型也无法与其对接,因而上层图形系统可以通过 hdi 接口,来直接操控显示屏。
display驱动开发指导
驱动开发说明
基于 hdf display 驱动模型,开发一款器件驱动,开发者主要需要完成两部分工作:hcs 配置文件、器件驱动层适配。
对于轻量级设备(l0-l1),以海思 hi35xx 芯片为例,除了上述两部分工作外,还需要在芯片平台适配层中,完成 soc 有关显示屏的硬件资源配置。
对于标准设备(≥l2),还需要关注与 drm 对接的标准架构适配层,此部分在模型中已经添加,开发者只需聚焦器件驱动层的实现即可。
具体开发步骤
此处我们以润和开发板(hi3516 soc)为例,说明适配一款 lcd 屏需要完成的工作。
添加 display 配置信息
(1)设备描述配置
配置文件目录:
vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs
基础的设备描述信息,在 hdf 的配置章节有作说明,此处不再重复描述。在配置文件中添加 lcd 设备描述信息如下:
device_lcd :: device { device0 :: devicenode { policy = 0; // 设备发布策略为0,即只对内核态发布服务 priority = 100; // 设备对应驱动加载优先级,值越小越早加载 preload = 0; // 0代表正常加载,1代表不加载 permission = 0660; // 设备对应节点的权限// 模块名很关键,需和对应驱动的中的modulename保持一致 modulename = “lcd_xxx”; servicename = “hdf_lcdxxx_service”; // 当前设备对应的服务 devicematchattr = “ hdf_lcdxxx_driver”; // 设备对应私有配置属性名 }}
(2)器件私有配置
参考的配置文件目录:
vendor/hisilicon/hispark_taurus/config/lcd/lcd_config.hcs
检查配置宏
驱动模型的编译入口:drivers/adapter/khdf/liteos/model/display/makefile
根据编译控制内容可知,需增加 panel 对应的编译控制宏:
ifeq ($(loscfg_drivers_hdf_lcd_xxx), y)local_srcs += $(liteostopdir)/。。/。。/drivers/framework/model/display/driver/panel/mipi_xxx.cendif
配置编译宏的路径:
kernel/liteos_a/tools/build/config/hispark_taurus_clang_release.config
loscfg_drivers_hdf_disp=yloscfg_drivers_hdf_lcd_xxx=y
适配器件驱动
display 驱动模型路径:drivers/framework/model/display/driver
对应的器件驱动路径:drivers/framework/model/display/driver/panel
驱动入口模板如下:
struct hdfdriverentry g_ xxxdeventry = { .moduleversion = 1, .modulename = “lcd_xxx”, // 要求和device_info.hcs中配置的模块名一致 .init = xxxentryinit, // 驱动入口};hdf_init(g_xxxdeventry); // hdf驱动入口解析模板
lcd 器件驱动需要适配的基础接口包括 init、on、off、setbacklight 等,并将器件信息挂接到 panle 的 info 成员上。
static void xxxpanelinit(struct paneldata *panel){ panel-》info = &g_panelinfo; panel-》status.powerstatus = power_status_off; panel-》status.currlevel = min_level; panel-》esd = &g_panelesd; panel-》init = xxxinit; panel-》on = xxxon; panel-》off = xxxoff; panel-》setbacklight = xxxsetbacklight;}
display开发实例
当前润和开源板(hi3516 soc)上搭载的是众盛捷的 5.5 寸屏,对应的 driver ic 型号为集创北方 icn9700,显示屏的物理接口为 mipi dsi,以此屏为例进行开发示例说明。
添加配置
配置路径:
vendor/hisilicon/hispark_taurus/config/device_info/device_info.hcs
/* display驱动相关的设备描述配置 */display :: host { hostname = “display_host”; /* display平台驱动设备描述 */ device_hdf_disp :: device { device0 :: devicenode { policy = 2; priority = 200; permission = 0660; modulename = “hdf_disp”; servicename = “hdf_disp”; } } /* soc适配层驱动设备描述 */ device_hi35xx_disp :: device { device0 :: devicenode { policy = 0; priority = 199; modulename = “hi351xx_disp”;
} } /* lcd器件驱动设备描述 */ device_lcd :: device { device0 :: devicenode { policy = 0; priority = 100; preload = 0; modulename = “lcd_ icn9700”; } }}
通过如上配置中的器件驱动的 modulename 为 “lcd_icn9700”,hdf 遍历对应的驱动入口并加载匹配的驱动。
适配编译
编译入口:drivers/adapter/khdf/liteos/model/display/makefile
ifeq ($(loscfg_drivers_hdf_lcd_icn9700), y)local_srcs += $(liteostopdir)/。。/。。/drivers/framework/model/display/driver/panel/mipi_icn9700.cendif
配置编译宏的路径:
kernel/liteos_a/tools/build/config/hispark_taurus_clang_release.config
loscfg_drivers_hdf_lcd_icn9700 =y
添加器件驱动
驱动路径:drivers/framework/model/display/driver/panel/mipi_icn9700.c
器件驱动加载入口:
struct hdfdriverentry g_icn9700deventry = { .moduleversion = 1, .modulename = “lcd_icn9700”, .init = icn9700entryinit,};
器件驱动初始化及 panel 注册:
int32_t icn9700entryinit(struct hdfdeviceobject *object){ struct icn9700dev *icn9700 = null; if (object == null) { hdf_loge(“%s: object is null”, __func__); return hdf_failure; } icn9700 = (struct icn9700dev *)osalmemcalloc(sizeof(struct icn9700dev)); if (icn9700 == null) { hdf_loge(“%s icn9700 malloc fail”, __func__); return hdf_failure; } icn9700panelinit(&icn9700-》panel);
icn9700-》panel.object = object; icn9700-》reset_gpio = reset_gpio; icn9700-》reset_delay = 20; // delay 20ms object-》priv = (void *)icn9700; if (registerpanel(&icn9700-》panel) != hdf_success) { hdf_loge(“%s: registerpanel failed”, __func__); return hdf_failure; } hdf_logi(“%s: exit succ”, __func__); return hdf_success;}
panel info 初始化:
static struct panelinfo g_panelinfo = { .width = width, /* width */ .height = height, /* height */ .hbp = horizontal_back_porch,
/* horizontal back porch */ .hfp = horizontal_front_porch, /* horizontal front porch */ .hsw = horizontal_sync_width, /* horizontal sync width */ .vbp = vertical_back_porch, /* vertical back porch */ .vfp = vertical_front_porch, /* vertical front porch */ .vsw = vertical_sync_width, /* vertical sync width */ .framerate = frame_rate, /* frame rate */ .intftype = mipi_dsi, /* panel interface type */ .intfsync = output_user,
/* output timing type */ /* mipi config info */ .mipi = { dsi_2_lanes, dsi_video_mode, video_burst_mode, format_rgb_24_bit }, /* backlight config info */ .blk = { blk_pwm, min_level, max_level, default_level }, .pwm = { blk_pwm1, pwm_max_period },};
填充 panel 信息并挂接回调接口:
static struct panelesd g_panelesd = { .support = false, .checkfunc = icn9700esdcheckfunc,};static void icn9700panelinit(struct paneldata *panel){ panel-》info = &g_panelinfo; panel-》status.powerstatus = power_status_off; panel-》status.currlevel = min_level; panel-》esd = &g_panelesd; panel-》init = icn9700init; panel-》on = icn9700on; panel-》off = icn9700off; panel-》setbacklight = icn9700setbacklight;}
panel 亮屏接口实现:
static int32_t icn9700on(struct paneldata *panel){ int32_t ret; struct icn9700dev *icn9700 = null; icn9700 = paneltoicn9700dev(panel); if (icn9700 == null) { hdf_loge(“%s: icn9700 is null”, __func__); return hdf_failure; } /* lcd reset power on */ ret = lcdreseton(icn9700); if (ret != hdf_success) { hdf_loge(“%s: lcdreseton failed”, __func__);
return hdf_failure; } if (icn9700-》mipihandle == null) { hdf_loge(“%s: mipihandle is null”, __func__); return hdf_failure;
} /* send mipi init code */ int32_t count = sizeof(g_oncmd) / sizeof(g_oncmd[0]); int32_t i; for (i = 0; i 《 count; i++) { ret = mipidsitx(icn9700-》mipihandle, &(g_oncmd[i])); if (ret != hdf_success) { hdf_loge(“%s: mipidsitx failed”, __func__); return hdf_failure; } } panel-》status.powerstatus = power_status_on; /* set mipi to hs mode */ mipidsisethsmode(icn9700-》mipihandle);
添加芯片适配驱动
驱动路径:
drivers/framework/model/display/driver/adapter_soc/hi35xx_disp.c
部分代码示例如下,mipi 参数配置:
static int32_t mipidsiinit(struct panelinfo *info){ int32_t ret; struct devhandle *mipihandle = null; struct mipicfg cfg; mipihandle = mipidsiopen(0); if (mipihandle == null) { hdf_loge(“%s: mipidsiopen failed”, __func__); return hdf_failure; } cfg.lane = info-》mipi.lane; cfg.mode = info-》mipi.mode;
cfg.format = info-》mipi.format; cfg.burstmode = info-》mipi.burstmode; cfg.timing.xpixels = info-》width;cfg.timing.hsapixels = info-》hsw; cfg.timing.hbppixels = info-》hbp; cfg.timing.hlinepixels = info-》width + info-》hbp + info-》hfp + info-》hsw; cfg.timing.vsalines = info-》vsw; cfg.timing.vbplines = info-》vbp;cfg.timing.vfplines = info-》vfp; cfg.timing.ylines = info-》height; cfg.timing.edpicmdsize = 0;cfg.pixelclk = calcpixelclk(info);
cfg.phydatarate = calcdatarate(info); /* config mipi device */ ret = mipidsisetcfg(mipihandle, &cfg); if (ret != hdf_success) { hdf_loge(“%s:mipidsisetcfg failed”, __func__); } mipidsiclose(mipihandle); return ret;}
总结
本文简要说明了 hdf display 驱动模型的整体架构、加载及运行流程、以及开发者基于此模型开发一款 lcd 驱动需要完成的基础适配工作。当前模型更多的是聚焦对各显示框架和差异化 soc 的兼容适配,优先满足不同开发板的基本显示功能需求,驱动模型还在不断演进完善,欢迎持续关注。


SKI在中国与匈牙利建设15GWh生产基地
勒夫迈|为什么要在空调机中内置粉尘传感器?空调机内置粉尘传感器的好处
安达发|基于APS排程系统的PDM功能
开启边缘计算新体验-Silicon Labs EFR32xG24 开发套件测评
领途携五款小型电动汽车亮相发布会
HDF Display驱动模型的整体架构加载及运行流程
煤气报警器电路图
国内外主机厂加快在华新能源汽车市场布局
智能家居是否可以借助5G大爆发
瑞萨电子推出面向物联网基础设施系统的 第二代多相数字控制器和智能功率级单元模块(SPS)
ios10.3系统进一步修复,听说果粉们都换了最新的iOS10.3系统
从键盘输入10个整数,以二进制形式输出到“outFile”中
微流控芯片装置与活细胞动态观察技术用于神经元轴突损伤机制研究
特斯拉已申请召回9136辆来自美国地区的Model X以及401辆Model Y
未来3年上海将累计投入超过300亿元建设新型无线城市
第八届“鼎阳杯”全国高校电工电子基础课程实验教学案例设计竞赛圆满谢幕
索尼触觉反馈手套专利 虚拟现实更近了
雅特力即将亮相ELEXCON 2022,诚邀您莅临1S11展位
低功耗低噪声Σ-Δ型(ADC)SC3794、AD7793适用于热电偶测温系统
物流供应链管理是什么,供应链物流管理系统的介绍