- Display 子系统
1.Display驱动模型介绍
当前操作系统和 SOC 种类繁多,各厂商的显示屏器件也各有不同,随之针对器件的驱动代码也不尽相同,往往是某一款器件驱动,只适用于某单一内核系统或 SOC,如果要迁移到其他内核或者 SOC,可能会有不小的移植工作量。而且,不同驱动 IC 的驱动代码差异较大,产品更换驱动 IC,则又需要重新开发对应的器件驱动,造成重复工作。因此基于 HDF 驱动框架,编写一套较通用的 Display 器件驱动模型,尽可能降低驱动开发者的开发或移植工作量,简化器件驱动开发,提升开发效率。
Display驱动编程,通过对显示器上电、初始化显示器驱动IC(Integrated Circuit)内部寄存器等操作,使其可以正常工作。基于HDF(Hardware Driver Foundation)驱动框架构建的Display驱动模型作用如下:
-
为LCD器件驱动开发提供了基础驱动框架,提升驱动开发效率。
-
便于开发的器件驱动实现跨OS、跨芯片平台迁移。
基于HDF驱动框架的Display驱动模型如下所示:
模型各层设计说明:
-
Display 驱动模型基于 HDF 驱动框架、Platform 接口及 OSAL 接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为 LCD 器件提供统一的驱动模型。
-
当前 HDF Display 驱动模型主要分为四层:标准架构适配层(DRM Panel Adapter Driver)、显示公共驱动层(Display Common Driver)、芯片平台适配层(SoC Adapter Driver)、器件驱动层(Display Panel Driver)。
1.1.标准架构适配层
- drivers_hdf_core\framework\model\display\driver\hdf_drm_panel.c
本层主要完成对接标准的显示驱动架构,如 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,
};
1.2.显示公共驱动层
- drivers_hdf_core\framework\model\display\driver\hdf_disp.c
此部分属于整个驱动模型的中枢,所有的屏端接口注册、Panel 信息管理、屏幕状态控制、用户态 HDI 接口命令处理、以及通用的基础显示特性,目前都是通过这部分实现。
在本层通过结构体 DispManager 管理所有的显示信息,其成员 PanelManager 用于记录与显示屏相关的接口及参数信息。同时接收并处理 HDI 层直接对 panel 操作相关的指令(主要用于 L0-L1 等轻量级系统),如 Panel 器件信息的获取、休眠唤醒、背光设置等指令。此外,本层还负责实现一些基础显示特性的业务框架,如 ESD 检查机制,力求将显示相关的共有逻辑集中到本层实现,以简化 Panel 器件驱动的实现,避免 panel 驱动中相同功能的重复实现,便于统一管理和维护。
1.3.芯片平台适配层
借助此 SoC 适配层,实现 Display 器件驱动和 SoC 侧硬件资源的解耦,主要完成芯片平台强相关的参数配置,如 mipi 速率计算及设置、管脚复用配置,以及其他和 SoC 强相关的差异化配置及初始化等。
1.4.器件驱动层
- drivers_hdf_core\framework\model\display\driver\panel
器件驱动层主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、休眠唤醒流程、背光设置、ESD 检测等,同时完成 panel 信息的解析,并将 panel 向上注册到公共驱动层进行管理。
1.5.驱动加载及运行
HDF 的驱动的加载方式,框架通过解析设备描述的 hcs 配置文件,获取到各设备的配置信息,根据 moduleName 来匹配对应设备的驱动文件入口,按照配置的加载优先级,依次加载驱动。
加载流程分为 9 步,分别说明如下:
- HDF Device Manager 解析设备描述;
- HDF 优先加载器件驱动层,构建 Panel 设备;
- 将 panel信息及操作接口注册到公共驱动层;
- HDF 其次加载芯片平台适配层,进行 SoC 相关硬件资源初始化;
- HDF再次加载公共驱动层,对共有特性进行初始化;
- HDF 最后加载标准架构适配层;
- 从公共驱动层中获取到 PanelManager,;
- 将对应panel 注册到 DRM 框架中;
- 在系统运行起来后,DRM 会调用 panel ops 进行显示屏控制。
备注:
对于LiteOS 这种轻量内核的系统,不会像 Linux 内核那样提供标准的显示框架,驱动模型也无法与其对接,因而上层图形系统可以通过 HDI 接口,来直接操控显示屏。
2.LCD接口
LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口。
-
MIPI DSI接口
MIPI DSI接口是MIPI(Mobile Industry Processor Interface)联盟定义的显示接口,主要用于移动终端显示屏接口,接口数据传输遵循MIPI协议,MIPI DSI接口为数据接口,传输图像数据,通常情况下MIPI DSI接口的控制信息以MIPI包形式通过MIPI DSI接口发送到对端IC,不需要额外的外设接口。
-
TTL接口
TTL接口是并行方式传输数据的接口,有数据信号、时钟信号和控制信号(行同步、帧同步、数据有效信号等),在控制信号控制下完成数据传输。通常TTL接口的LCD,内部寄存器读写需要额外的外设接口,比如SPI接口、I2C接口等。
3.HDF LCD 驱动
3.1.LCD 内核配置
- Kconfig\Makefile
drivers_hdf_core\adapter\khdf\linux\model\display\Kconfig:
config DRIVERS_HDF_DISP
bool "Enable HDF Display driver"
default n
depends on DRIVERS_HDF
help
Answer Y to choice HDF Display driver.
config DRIVERS_HDF_LCDKIT
bool "Enable HDF Lcdkit driver"
default n
depends on DRIVERS_HDF_DISP
help
Answer Y to enable HDF Lcdkit driver.
config DRIVERS_HDF_LCD_ICN9700
bool "Enable HDF Icn9700 driver"
default n
depends on DRIVERS_HDF_DISP
help
Answer Y to enable HDF Icn9700 driver.
drivers_hdf_core\adapter\khdf\linux\model\display\Makefile:
KHDF_DISPLAY_BASE_ROOT_DIR = ../../../../../../..
DISPLAY_ROOT_DIR = ../../../../../framework/model/display/driver
ifeq ($(CONFIG_DRIVERS_HDF_DISP), y)
obj-y += \
$(DISPLAY_ROOT_DIR)/hdf_disp.o \
$(DISPLAY_ROOT_DIR)/backlight/hdf_bl.o
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
ifeq ($(CONFIG_ARCH_ROCKCHIP), y)
obj-y += $(DISPLAY_ROOT_DIR)/hdf_drm_panel.o
endif
#endif
obj-$(CONFIG_DRIVERS_HDF_PLATFORM_PWM) += \
$(DISPLAY_ROOT_DIR)/backlight/pwm_bl.o
obj-$(CONFIG_ARCH_SPRD) += \
$(DISPLAY_ROOT_DIR)/panel/ili9881c_boe.o
obj-$(CONFIG_ARCH_HI3516DV300) += \
$(DISPLAY_ROOT_DIR)/adapter_soc/hi35xx_disp.o
obj-$(CONFIG_DRIVERS_HDF_LCDKIT) += \
$(DISPLAY_ROOT_DIR)/lcdkit/lite_lcdkit.o \
$(DISPLAY_ROOT_DIR)/lcdkit/lcdkit_parse_config.o
...
ccflags-y += -lm -lc -lgcc \
-I$(srctree)/drivers/hdf/framework/model/display/driver \
-I$(srctree)/drivers/hdf/framework/model/display/driver/adapter_soc \
...
ccflags-y +=-I$(srctree)/bounds_checking_function/include
endif
3.2.LCD 设备配置
- 配置设备描述信息(vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs)
驱动注册到 HDF 框架所需要的设备驱动描述信息,如驱动是否加载以及加载次序等。device_info.hcs 中的信息主要提供给 HDF 框架使用,包含了 Input 模型各层驱动注册到 HDF 框架所必需的信息,开发者无特殊场景需求无需改动。各驱动层私有配置信息通过**“deviceMatchAttr”字段与 input_config.hcs 中的“match_attr”**相关内容进行匹配。
237 display :: host {
238 hostName = "display_host";
239 device_hdf_drm_panel :: device {
240 device0 :: deviceNode {
241 policy = 0;
242 priority = 197;
243 preload = 0;
244 moduleName = "HDF_DRMPANEL";
245 }
246 }
/* Display平台驱动设备描述 */
247 device_hdf_disp :: device {
248 device0 :: deviceNode {
249 policy = 2;
250 priority = 196;
251 permission = 0660;
252 moduleName = "HDF_DISP";
253 serviceName = "hdf_disp";
254 }
255 }
/* SOC适配层驱动设备描述 */
256 device_hi35xx_disp :: device {
257 device0 :: deviceNode {
258 policy = 0;
259 priority = 195;
260 moduleName = "HI351XX_DISP";
261 }
262 }
/* LCD器件驱动设备描述 */
263 device_lcd :: device {
271 ...
283 device3 :: deviceNode {
284 policy = 0;
285 priority = 100;
286 preload = 0;
287 moduleName = "LCD_ILI9881_ST_5P5";
288 }
289 }
290 device_pwm_bl :: device {
291 device0 :: deviceNode {
292 policy = 0;
293 priority = 95;
294 preload = 0;
295 moduleName = "PWM_BL";
296 deviceMatchAttr = "pwm_bl_dev";
297 }
298 }
299 device_backlight :: device {
300 device0 :: deviceNode {
301 policy = 2;
302 priority = 90;
303 preload = 0;
304 permission = 0660;
305 moduleName = "HDF_BL";
306 serviceName = "hdf_bl";
307 }
308 }
309 }
- .板级配置及器件私有配置(vendor/hihope/rk3568/hdf_config/khdf/lcd/lcd_config.hcs )
1 root {
2 backlightConfig {
3 pwmBacklightConfig {
4 match_attr = "pwm_bl_dev";
5 pwmDevNum = 1;
6 pwmMaxPeriod = 25000;
7 backlightDevName = "hdf_pwm";
8 minBrightness = 0;
9 defBrightness = 127;
10 maxBrightness = 255;
11 }
12 }
13 }
3.3.驱动实现
- 对于LCD类型的设备,公共驱动框架已实现。
drivers_hdf_core\framework\model\display\driver\hdf_drm_panel.c
drivers_hdf_core\framework\model\display\driver\hdf_disp.c
drivers_hdf_core\framework\model\display\driver\backlight\hdf_bl.c
drivers_hdf_core\framework\model\display\driver\backlight\pwm_bl.c
-
适配 ili9881_st_5p5 需要完成器件层驱动初始化、释放资源、注册驱动至HDF框架。
drivers_hdf_core\framework\model\display\driver\panel\ili9881_st_5p5.c
3.3.1.ssp_st7789器件驱动
1).注册到HDF框架
struct HdfDriverEntry PanelDevEntry = {
.moduleVersion = 1,
.moduleName = "LCD_ILI9881_ST_5P5",
.Init = PanelEntryInit,
};
HDF_INIT(PanelDevEntry);
2).器件层驱动初始化
struct panel_ili9881_dev {
bool power_invert;
struct PanelData panel; //重要数据结构
struct mipi_dsi_device *dsiDev;
struct regulator *supply;
struct gpio_desc *enable_gpio;
struct gpio_desc *reset_gpio;
struct gpio_desc *hpd_gpio;
struct panel_hw_delay hw_delay;
};
struct PanelData {
struct HdfDeviceObject *object;
int32_t (*init)(struct PanelData *panel);
int32_t (*on)(struct PanelData *panel);
int32_t (*off)(struct PanelData *panel);
int32_t (*prepare)(struct PanelData *panel);
int32_t (*unprepare)(struct PanelData *panel);
struct PanelInfo *info;
enum PowerStatus powerStatus;
struct PanelEsd *esd;
struct BacklightDev *blDev;
void *priv;
};
static int32_t PanelEntryInit(struct HdfDeviceObject *object)
{
struct device_node *panelNode = NULL;
struct panel_ili9881_dev *panel_dev = NULL;
panel_dev = (struct panel_ili9881_dev *)OsalMemCalloc(sizeof(struct panel_ili9881_dev));
g_panel_dev = panel_dev;
panelNode = of_find_compatible_node(NULL, NULL, "simple-panel-dsi");
panel_dev->dsiDev = of_find_mipi_dsi_device_by_node(panelNode);
panel_dev->supply = devm_regulator_get(&panel_dev->dsiDev->dev, "power");
if (PanelRequestGpio(panel_dev) != HDF_SUCCESS) {
goto FAIL;
}
PanelResInit(panel_dev);
panel_dev->panel.object = object;
object->priv = panel_dev;
if (RegisterPanel(&panel_dev->panel) != HDF_SUCCESS) {
...
}
return HDF_SUCCESS;
}
- 申请struct panel_ili9881_dev结构体,根据"simple-panel-dsi"查找内核设备数节点panelNode;
- 获取plane 供电regulator和gpio 引脚;
- 调用 PanelResInit进行初始化panel结构体;
Panel 操作函数有:
panel_dev->panel.init = PanelInit;
panel_dev->panel.on = PanelOn;
panel_dev->panel.off = PanelOff;
panel_dev->panel.prepare = PanelPrepare;
panel_dev->panel.unprepare = PanelUnprepare;
- 调用RegisterPanel 注册panel到g_panelManager。
3.3.2. HDF LCD 公共驱动层
3.3.2.1.HDF_DISP
- 结构体
drivers_hdf_core\framework\model\display\driver\hdf_disp.h
struct DispManager {
struct PanelManager *panelManager;
struct OsalMutex dispMutex;
HdfWorkQueue dispWorkQueue;
bool initialzed;
struct DispEsd *esd;
};
struct PanelManager {
struct PanelData *panel[PANEL_MAX];
uint32_t panelNum;
};
- 初始化及注册驱动至HDF框架
drivers_hdf_core\framework\model\display\driver\hdf_disp.c
struct HdfDriverEntry g_dispDevEntry = {
.moduleVersion = 1,
.moduleName = "HDF_DISP",
.Init = HdfDispEntryInit,
.Bind = HdfDispBind,
};
HDF_INIT(g_dispDevEntry);
- .Init = HdfDispEntryInit,
DispManagerInit初始化struct DispManager ,将 panelManager 注册到g_dispManager->panelManager,然后创建一个工作队列 HdfWorkQueueInit(&g_dispManager->dispWorkQueue, “dispWQ”); - .Bind = HdfDispBind,
绑定服务HdfDispDispatch,调用DispCmdProcess通过g_dispCmdHandle进行显示命令处理。
static int HdfDispBind(struct HdfDeviceObject *dev)
{
if (dev == NULL) {
return HDF_FAILURE;
}
static struct IDeviceIoService dispService = {
.object.objectId = 1,
.Dispatch = HdfDispDispatch,
};
dev->service = &dispService;
return HDF_SUCCESS;
}
DispCmdHandle g_dispCmdHandle[] = {
GetPowerStatus,
GetInfo,
SetPowerStatus,
SetBacklight,
GetBacklight,
};
3.3.2.2.HDF_DRMPANEL
- 结构体
drivers_hdf_core\framework\model\display\driver\hdf_drm_panel.h
struct HdfDrmPanel {
struct drm_panel panel;
struct DispManager *manager;
struct drm_display_mode mode;
struct mipi_dsi_device *dsiDev;
uint32_t index;
};
- 初始化及注册驱动至HDF框架
drivers_hdf_core\framework\model\display\driver\hdf_drm_panel.c
struct HdfDriverEntry g_hdfDrmPanelEntry = {
.moduleVersion = 1,
.moduleName = "HDF_DRMPANEL",
.Init = HdfDrmPanelEntryInit,
};
refer to
- https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-peripherals-lcd-des.md
- https://blog.csdn.net/HarmonyOS_666/article/details/140824498?spm=1001.2101.3001.6650.7&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-140824498-blog-143099522.235%5Ev43%5Epc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-7-140824498-blog-143099522.235%5Ev43%5Epc_blog_bottom_relevance_base2&utm_relevant_index=8