OpenHarmony南向之LCD显示屏
概述
LCD(Liquid Crystal Display)驱动,通过对显示器上下电、初始化显示器驱动IC(Integrated Circuit)内部寄存器等操作,使其可以正常工作。
HDF Display驱动模型
LCD器件驱动是显示框架最底层的部分。
向上对接到 Display 公共 HAL 层,辅助 HDI 的实现。通过Display-HDI对图形服务提供各类驱动能力接口;
向下对接显示屏 panel 器件,驱动屏幕正常工作,自上而下打通显示全流程通路。
所以驱动LCD主要在于LCD panel器件驱动。
LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,这里以rk3568平台为例,是常见的mipi接口的显示屏
驱动主要分为2大部分:hcs配置和panel驱动
- vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs
- drivers/hdf_core/framework/model/display/driver/panel/
下面就这2大部分分别来简单分析下
hcs配置及流程
hcs配置
display :: host {
hostName = "display_host";
device_hdf_drm_panel :: device {
device0 :: deviceNode {
policy = 0;
priority = 197;
preload = 0;
moduleName = "HDF_DRMPANEL";
}
}
device_hdf_disp :: device {
device0 :: deviceNode {
policy = 2;
priority = 196;
permission = 0660;
moduleName = "HDF_DISP";
serviceName = "hdf_disp";
}
}
device_lcd :: device {
...
device3 :: deviceNode {
policy = 0;
priority = 100;
preload = 0;
moduleName = "LCD_ILI9881_ST_5P5";
}
}
device_pwm_bl :: device {
device0 :: deviceNode {
policy = 0;
priority = 95;
preload = 0;
moduleName = "PWM_BL";
deviceMatchAttr = "pwm_bl_dev";
}
}
device_backlight :: device {
device0 :: deviceNode {
policy = 2;
priority = 90;
preload = 0;
permission = 0660;
moduleName = "HDF_BL";
serviceName = "hdf_bl";
}
}
}
大致流程
从上面的hcs配置可以看出,这里使用的是 DRM Panel,根据 priority值,驱动加载的顺序依次为:
1:HDF_BL:
2:PWM_BL
3:LCD
4:HDF_DISP
5:HDF_DRMPANEL
这个顺序是跟驱动代码里面的逻辑是相匹配的,LCD驱动在init的时候会注册panel(RegisterPanel),然后在HDF_DISP驱动的init中会通过 GetPanelManager获取注册的panelManager, 并使用 panelManager来 DispManagerInit,HDF_DRMPANEL驱动在init的时候会通过 GetDispManager获取在前面初始化的 DispManager,并使用DRM框架的接口来init和add相应drm_panel,且将mipi接口联系起来,整个过程是环环相扣。
panel驱动
Panel驱动中最核心的主要是实现以下接口:
struct PanelData {
struct HdfDeviceObject *object;
int32_t (*init)(struct PanelData *panel); /*panel的软件初始化*/
int32_t (*on)(struct PanelData *panel); /*主要控制上电*/
int32_t (*off)(struct PanelData *panel); /*主要控制下电*/
int32_t (*prepare)(struct PanelData *panel); /*亮屏硬件时序初始化, 通过MIPI DCS发送亮屏初始化序列*/
int32_t (*unprepare)(struct PanelData *panel); /*灭屏硬件时序初始化, 通过MIPI DCS发送灭屏代码*/
struct PanelInfo *info; /*Panel的一些参数。见下方*/
enum PowerStatus powerStatus;
struct PanelEsd *esd;
struct BacklightDev *blDev;
void *priv;
};
在驱动初始化接口中实例化后使用 RegisterPanel接口向display模型注册该panel驱动
以 ili9881_st_5p5MIPI显示屏驱动为例来看看大致的流程:
...
/*获取panel节点,rk一般都使用的 simple panel*/
panelNode = of_find_compatible_node(NULL, NULL, "simple-panel-dsi");
if (panelNode == NULL) {
HDF_LOGE("%s of_find_compatible_node fail", __func__);
goto FAIL;
}
/*通过panel节点进一步获取mipi dsi的节点*/
panel_dev->dsiDev = of_find_mipi_dsi_device_by_node(panelNode);
if (panel_dev->dsiDev == NULL) {
HDF_LOGE("%s of_find_mipi_dsi_device_by_node fail", __func__);
goto FAIL;
}
/*获取power节点*/
panel_dev->supply = devm_regulator_get(&panel_dev->dsiDev->dev, "power");
if (panel_dev->supply == NULL) {
HDF_LOGE("Get regulator fail");
goto FAIL;
}
/*获取其他gpio控制节点,需根据硬件配置**/
panel_dev->enable_gpio = devm_gpiod_get_optional(&panel_dev->dsiDev->dev, "enable", GPIOD_ASIS);
if (IS_ERR(panel_dev->enable_gpio)) {
HDF_LOGE("get enable_gpio fail");
goto FAIL;
}
...
/*初始化PanelData mipi_dsi_device结构体,下面会展开详细说明*/
PanelResInit(panel_dev);
...
/*注册到Panel Manager*/
if (RegisterPanel(&panel_dev->panel) != HDF_SUCCESS) {
HDF_LOGE("RegisterPanel fail");
goto FAIL;
}
...
PanelResInit函数主要是关键结构体(struct PanelData和 struct mipi_dsi_device )的实例化:
/*mipi dsi 的一些参数*/
panel_dev->dsiDev->lanes = 4; /* 4: dsi,lanes ,number of active data lanes */
panel_dev->dsiDev->format = MIPI_DSI_FMT_RGB888; // dsi,format pixel format for video mode MIPI_DSI_FMT_RGB888
panel_dev->dsiDev->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM \
| MIPI_DSI_MODE_EOT_PACKET);
panel_dev->panel.info = &g_panelInfo; /*Panel的一些参数。见下方*/
panel_dev->panel.init = PanelInit; /*panel的软件初始化,这里为空函数*/
panel_dev->panel.on = PanelOn; /*主要控制上电*/
panel_dev->panel.off = PanelOff; /*主要控制下电*/
panel_dev->panel.prepare = PanelPrepare; /*亮屏硬件时序初始化, 通过MIPI DCS发送亮屏初始化代码*/
panel_dev->panel.unprepare = PanelUnprepare; /*灭屏硬件时序初始化, 通过MIPI DCS发送灭屏代码*/
panel_dev->panel.priv = panel_dev->dsiDev;
这里,在v3.2版本的代码里,最终还是调用的是Linux下mipi dsi相关的接口,并没有使用OH实现的mipi的驱动接口
panel相关的硬件参数定义,这个主要跟显示屏硬件有关,这些参数的具体含义可参看:《做鸿蒙应用开发到底学习些啥?》
static struct PanelInfo g_panelInfo = {
.width = 720, /* width */
.height = 1280, /* height */
.hbp = 40, /* horizontal back porch */
.hfp = 40, /* horizontal front porch */
.hsw = 10, /* horizontal sync width */
.vbp = 15, /* vertical back porch */
.vfp = 10, /* vertical front porch */
.vsw = 36, /* vertical sync width */
.clockFreq = 75000000, /* clock */
.pWidth = 68, /* physical width */
.pHeight = 121, /* physical height */
.connectorType = DRM_MODE_CONNECTOR_DPI, /* DRM_MODE_CONNECTOR_DPI=17 */
.blk = { BLK_PWM, MIN_LEVEL, MAX_LEVEL, DEFAULT_LEVEL },
};
总结
以上的内容主要简单介绍了OpenHarmony南向之LCD显示屏,没有具体到代码分析,移植等细节。
要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。
为了节省大家一些查找的时间,这边联合几位行业大佬,为大家准备了一份《Open Harmony4.0&Next》的学习导图 ,从入门到进阶再到南北向开发实战的一整套完整体系 ,想要学习了解更多鸿蒙开发的相关知识可以借鉴:《做鸿蒙应用开发到底学习些啥?》
除了以上的知识内容,我还为大家整理了一份**《鸿蒙 (Harmony OS)开发学习手册》都是整理成PDF文档方式,分享给大家参考学习:《鸿蒙开发学习指南》**
《鸿蒙 (Harmony OS)开发学习手册》
一、入门必看
-
应用开发导读(ArkTS)
-
应用开发导读(Java)
3.......
二、HarmonyOS 概念
-
系统定义
-
技术架构
-
技术特性
-
系统安全
5......
三、如何快速入门?《鸿蒙基础入门开发宝典!》
-
基本概念
-
构建第一个ArkTS应用
-
构建第一个JS应用
-
......
四、开发基础知识
-
应用基础知识
-
配置文件
-
应用数据管理
-
应用安全管理
-
应用隐私保护
-
三方应用调用管控机制
-
资源分类与访问
-
学习ArkTS语言
-
......
五、基于ArkTS 开发
-
Ability开发
-
UI开发
-
公共事件与通知
-
窗口管理
-
媒体
-
安全
-
网络与链接
-
电话服务
-
数据管理
-
后台任务(Background Task)管理
-
设备管理
-
设备使用信息统计
-
DFX
-
国际化开发
-
折叠屏系列
-
......
更多了解更多鸿蒙开发的相关知识可以参考:《做鸿蒙应用开发到底学习些啥?》