Graphic display system

From wiki
Jump to: navigation, search


前言

为了点亮一块MIPI屏幕,我们除了要了解MIPI DSI的工作原理之外,大前提是要了解整个MIPI DSI图显系统的组成,更需要清楚点亮一块MIPI屏幕需要做哪些事情。在DRM架构下,提供了drm_mipi_dsi.c、drm_panel.c以及drm_bridge.c三个核心文件。用户的MIPI DSI驱动以drm_mipi_dsi.c为核心进行代码编写,例如RK3399的MIPI驱动dw-mipi-dsi.c。各显示屏厂商的驱动代码基于后两者进行编写,例如较为广泛使用的panel-simple.c。 linux平台普遍采用的DRM软件架构中,不仅包含了内核空间驱动层的代码,而且提供应用层的支撑库libdrm。libdrm基于DRI协议通过ioctl与2D图显驱动进行交互,配置图显处理器以及HDMI、MIPI、LVDS等编解码单元。 目前的图显外设接口主要有 MIPI、HDMI、LVDS、DP、VGA、DVI、RGB 等等,同时,又可以通过转接卡来实现各种接口之间的转换。目前,市面上的处理器 SoC 又同时具备以上接口。因此,DRM 架构为了统一管理、无差别化对待不同芯片厂商的 IP,抽象出了 ENCODER 和 CONNECTOR 两部分内容。

DRM CRTC

DRM ENCODER

ENCODER 作为图显外设的逻辑控制器,从图显处理器接收并行的 RGB 数据,并按照接口类型对 RGB 数据进行编码,例如 HDMI 通过 encoder 将 RGB 数据编码为 TMDS 类型的数据。 在软件层面的 DRM 架构中规定了使用下面两个数据结构,注册 DRM ENCODER 相关功能。

//encoder控制
struct drm_encoder_funcs {
    void (*reset)(struct drm_encoder *encoder);
    void (*destroy)(struct drm_encoder *encoder);
    int (*late_register)(struct drm_encoder *encoder);
    void (*early_unregister)(struct drm_encoder *encoder);
};
//encoder配置
struct drm_encoder_helper_funcs {
    void (*dpms)();
    enum drm_mode_status ();
    bool (*mode_fixup)();
    void (*prepare)();
    void (*commit)();
    void (*mode_set)();
    void (*atomic_mode_set)();
    struct drm_crtc *(*get_crtc)();
    enum drm_connector_status ();
    void (*atomic_disable)();
    void (*atomic_enable)();
    void (*disable)();
    void (*enable)();
    int (*atomic_check)();
};

DRM PANEL

DRM PLANE 从 drm_framebuffer 接收数据,构造图像的雏形,完成图像的剪裁和缩放后发送到&drm_crtc。 除此之外,还通过 drm_plane_state 来提供图像旋转功能。 剪裁通过改变由 framebuffer 送过来的图显数据 W/H 值来实现; 缩放通过改变 plane 和 crtc 定义的 W/H 来实现; 多图层叠加通过指定 plane 中图显数据在 crtc 中的位置; PLANE 存在的意义主要有两点: 增强系统灵活性 对于桌面系统而言,显示器背景图案和鼠标光标通常是基本的显示元素,并且一直存在直到系统关机。因此,对于这种变化不是很频繁的基本图显输出,可以由通用 plane 来实现。而那些频繁变化的图显输出,交由专用的 plane 来实现。 提高系统性能 由于 plane 具备图像缩放、剪裁、多图层叠加等功能,因此,可以让 GPU 来将更多的精力放在图形渲染上,这种基本的图像处理交由 plane 实现。 PLANE 的初始化和功能 在 plane 初始化之前,各 SoC 厂商需要例化一个类似于 exynos_drm_plane_config 这样的数据结构,用于描述各个图册的属性、plane 支持的像图像格式等,按照前文的描述,exynos 也是支持 3 各图层的,可以实现 3 帧图像的叠加。

static const struct exynos_drm_plane_config
plane_configs[MIXER_WIN_NR] = {
    {
        .zpos = 0,
        .type = DRM_PLANE_TYPE_PRIMARY,
        .pixel_formats = mixer_formats,
        .num_pixel_formats = ARRAY_SIZE(mixer_formats),
        .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | EXYNOS_DRM_PLANE_CAP_ZPOS,
    },
    {
        .zpos = 1,
        .type = DRM_PLANE_TYPE_CURSOR,
        .pixel_formats = mixer_formats,
        .num_pixel_formats = ARRAY_SIZE(mixer_formats),
        .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | EXYNOS_DRM_PLANE_CAP_ZPOS,
    },
    {
        .zpos = 2,
        .type = DRM_PLANE_TYPE_OVERLAY,
        .pixel_formats = vp_formats,
        .num_pixel_formats = ARRAY_SIZE(vp_formats),
        .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
                    EXYNOS_DRM_PLANE_CAP_ZPOS |
                    EXYNOS_DRM_PLANE_CAP_TILE,
    },

}; plane 的下列属性决定了图像显示的位置及缩放大小等,也可以单独设置 property 属性值

drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
drm_object_attach_property(&plane->base, config->prop_src_x, 0);
drm_object_attach_property(&plane->base, config->prop_src_y, 0);
drm_object_attach_property(&plane->base, config->prop_src_w, 0);
drm_object_attach_property(&plane->base, config->prop_src_h, 0);

DRM FRAMEBUFFER

frame buffers 是一个抽象出来的内存对象,用于向 CRTC 传递像素数据,在 kernel 中使用 struct drm_framebuffer 来描述fb。

struct drm_framebuffer {
    struct drm_device *dev;
    struct list_head head;
    struct drm_mode_object base;
    char comm[TASK_COMM_LEN];
    const struct drm_format_info *format;
    const struct drm_framebuffer_funcs *funcs;
    unsigned int pitches[4];
    unsigned int offsets[4];
    uint64_t modifier;
    unsigned int width;
    unsigned int height;
    int flags;
    int hot_x;
    int hot_y;
    struct list_head filp_head;
    struct drm_gem_object *obj[4];
};

通过 drm_framebuffer_init() 来例化 fb。实现 ID 分配、注册辅助函数列表、向 fd 链表注册。