程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Rockchip RK3399 - DRM crtc基础知识

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板
eMMC16GB
LPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot2023.04
linux6.3
----------------------------------------------------------------------------------------------------------------------------

一、LCD硬件原理

1.1 CRT介绍

CRT是阴极射线管(Cathode Ray Tube)的缩写,它是一种使用电子束在荧光屏上创建图像的显示设备。CRT显示器在过去很长一段时间内是主流的显示技术,现已被液晶显示屏(LCDLiquid Crystal Display)或其他新兴技术所替代。

CRT显示器中,扫描电子束从左到右、从上到下移动,照亮屏幕上的荧光点,从而创建图像。电子束每秒多次扫描整个屏幕,产生闪烁效果,需要与正在显示的内容同步。

随着LCDLEDOLED等新型显示技术的出现,底层原理已经发生了变化;

  • LCDLCD的构造是在两片平行的玻璃当中放置液态的晶体,两片玻璃中间有许多垂直和水平的细小电线,透过通电与否来控制杆状水晶分子改变方向,将光线折射出来产生画面; LCD通常需要背光源,例如冷阴极荧光灯(CCFL)或LED背光,以照亮液晶面板;这些背光源位于液晶面板的后面,因此LCD显示屏通常较厚;
  • LEDLED是一种通过控制半导体发光二极管的显示方式,其大概的样子就是由很多个通常是红色的发光二极管组成,靠灯的亮灭来显示字符,用来显示文字、图形、图像、动画、行情、视频、录像信号等各种信息的显示屏幕;LED显示屏的LED作为自身的背光源,这使得LED显示屏可以更薄,并且能效更高;
  • OLEDOLED显示屏使用有机发光二极管(OLED),每个像素都能发光,因此无需背光源;每个像素可以独立控制,实现高对比度和色彩鲜艳;

这些显示器不再使用扫描电子束,而是使用可以单独控制发光或阻挡光的像素矩阵。这使得图像更加清晰,刷新率更快,能源效率也得到了提高;

然而,刷新显示的基本概念并没有发生很大变化。显示内容仍然通过向每个像素发送信号来控制其亮度和颜色来进行更新。这些信号由显示控制器根据输入视频信号生成,并且它们确定屏幕上显示的内容。

1.2 LCD示意图

下图是LCD显示器示意图,里面的每个点就是一个像素点。它里面有一个电子枪,一边移动,一边发出各种颜色的光。用动态图表示如下:

img

电子枪是如何移动的?

  • 有一条Pixel Clock时钟线与LCD相连,每发出一次Pixel Clock,电子枪就移动一个像素。

颜色如何确定?

  • 由连接LCD的三组线RGB三原色混合而成:R(Red)、G(Green)、B(Blue)确定。

电子枪如何得知应跳到下一行?

  • 有一条HSYNC信号线与LCD相连,每发出一次脉冲(高低电平),电子枪就跳到下一行,该信号叫做行同步信号。

电子枪如何得知应跳到原点?

  • 有一条VSYNC信号线与LCD相连,每发出一次脉冲(高低电平),电子枪就跳到原点,该信号叫做帧同步信号。

RGB线上的数据从何而来?

  • 内存里面划分一块显存(frameBuffer),里面存放了要显示的数据,LCD控制器从里面将数据读出来,通过显示接口(比如mipilvdshdmiedpdp)传给电子枪,电子枪再依次打到显示屏上。
img

因此要想在显示设备上显示图像,至少需要3个信号:

  • Pixel Clock:时钟信号,在每个时钟周期更新屏幕上一个像素;
  • HSYNC:水平同步信号,引脚每发出一个脉冲,表示一行的数据开始发送;
  • VSYNC:垂直同步信号,引脚每发出一个脉冲,表示一帧的数据开始发送。

1.3 时序参数

在上图中我们发现除了Pixel ClockHSYNCVSYNC信号外,还包含了大量的时序参数,这里我们一一介绍:

  • HBPDhback porch):行同步信号的后肩,单位为1个Pixel Clock时钟周期;
  • HFPDhfront porch):行同步信号的前肩,单位为1个Pixel Clock时钟周期;
  • HSPWhsync pulse):行同步信号的脉宽,单位为1个Pixel Clock时钟周期;
  • HOZVALhdisplay):LCD的水平宽度;
  • VBPDvback porch):帧同步信号的后肩,单位为1个HSYNC时钟周期;
  • VFPDvfront porch):帧同步信号的前肩,单位为1个HSYNC时钟周期;
  • VSPWvsync pulse):帧同步信号的脉宽,单位为1个HSYNC时钟周期;
  • LINEVALvdisplay):LCD的垂直宽度;

如果这部分内容看不到,可以参考我之前写的这篇文章:Mini2440裸机开发之LCD基础

二、crtc数据结构

DRM框架中,crtcframebuffer中读取待显示的图像,并按照响应的格式输出给encoder,其主要承担的作用为:

  • 配置适合显示的显示模式、分辨率、刷新率等参数,并输出相应的时序;
  • 扫描framebuffer发送到一个或多个显示器;
  • 更新framebuffer

概括下就是,对显示器进行扫描,产生时序信号的模块、负责帧切换、电源控制、色彩调整等等。

2.1 struct drm_crtc

linux内核使用struct drm_crtc来表示一个crtc控制器,包括显示模式、分辨率、刷新率等参数。定义在include/drm/drm_crtc.h

/**
 * struct drm_crtc - central CRTC control structure
 *
 * Each CRTC may have one or more connectors associated with it.  This structure
 * allows the CRTC to be controlled.
 */
struct drm_crtc {
        /** @dev: parent DRM device */
        struct drm_device *dev;
        /** @port: OF node used by drm_of_find_possible_crtcs(). */
        struct device_node *port;
        /**
         * @head:
         *
         * List of all CRTCs on @dev, linked from &drm_mode_config.crtc_list.
         * Invariant over the lifetime of @dev and therefore does not need
         * locking.
         */
        struct list_head head;

        /** @name: human readable name, can be overwritten by the driver */
        char *name;

        /**
         * @mutex:
         *
         * This provides a read lock for the overall CRTC state (mode, dpms
         * state, ...) and a write lock for everything which can be update
         * without a full modeset (fb, cursor data, CRTC properties ...). A full
         * modeset also need to grab &drm_mode_config.connection_mutex.
         *
         * For atomic drivers specifically this protects @state.
         */
        struct drm_modeset_lock mutex;

        /** @base: base KMS object for ID tracking etc. */
        struct drm_mode_object base;

        /**
         * @primary:
         * Primary plane for this CRTC. Note that this is only
         * relevant for legacy IOCTL, it specifies the plane implicitly used by
         * the SETCRTC and PAGE_FLIP IOCTLs. It does not have any significance
         * beyond that.
         */
        struct drm_plane *primary;

        /**
         * @cursor:
         * Cursor plane for this CRTC. Note that this is only relevant for
         * legacy IOCTL, it specifies the plane implicitly used by the SETCURSOR
         * and SETCURSOR2 IOCTLs. It does not have any significance
         * beyond that.
         */
        struct drm_plane *cursor;
        /**
         * @index: Position inside the mode_config.list, can be used as an array
         * index. It is invariant over the lifetime of the CRTC.
         */
        unsigned index;

        /**
         * @cursor_x: Current x position of the cursor, used for universal
         * cursor planes because the SETCURSOR IOCTL only can update the
         * framebuffer without supplying the coordinates. Drivers should not use
         * this directly, atomic drivers should look at &drm_plane_state.crtc_x
         * of the cursor plane instead.
         */
        int cursor_x;
        /**
         * @cursor_y: Current y position of the cursor, used for universal
         * cursor planes because the SETCURSOR IOCTL only can update the
         * framebuffer without supplying the coordinates. Drivers should not use
         * this directly, atomic drivers should look at &drm_plane_state.crtc_y
         * of the cursor plane instead.
         */
        int cursor_y;

        /**
         * @enabled:
         *
         * Is this CRTC enabled? Should only be used by legacy drivers, atomic
         * drivers should instead consult &drm_crtc_state.enable and
         * &drm_crtc_state.active. Atomic drivers can update this by calling
         * drm_atomic_helper_update_legacy_modeset_state().
         */
        bool enabled;

        /**
         * @mode:
         *
         * Current mode timings. Should only be used by legacy drivers, atomic
         * drivers should instead consult &drm_crtc_state.mode. Atomic drivers
         * can update this by calling
         * drm_atomic_helper_update_legacy_modeset_state().
         */
        struct drm_display_mode mode;
        /**
         * @hwmode:
         *
         * Programmed mode in hw, after adjustments for encoders, crtc, panel
         * scaling etc. Should only be used by legacy drivers, for high
         * precision vblank timestamps in
         * drm_crtc_vblank_helper_get_vblank_timestamp().
         *
         * Note that atomic drivers should not use this, but instead use
         * &drm_crtc_state.adjusted_mode. And for high-precision timestamps
         * drm_crtc_vblank_helper_get_vblank_timestamp() used
         * &drm_vblank_crtc.hwmode,
         * which is filled out by calling drm_calc_timestamping_constants().
         */
        struct drm_display_mode hwmode;

        /**
         * @x:
         * x position on screen. Should only be used by legacy drivers, atomic
         * drivers should look at &drm_plane_state.crtc_x of the primary plane
         * instead. Updated by calling
         * drm_atomic_helper_update_legacy_modeset_state().
         */
        int x;
        /**
         * @y:
         * y position on screen. Should only be used by legacy drivers, atomic
         * drivers should look at &drm_plane_state.crtc_y of the primary plane
         * instead. Updated by calling
         * drm_atomic_helper_update_legacy_modeset_state().
         */
        int y;

        /** @funcs: CRTC control functions */
        const struct drm_crtc_funcs *funcs;

        /**
         * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up
         * by calling drm_mode_crtc_set_gamma_size().
         *
         * Note that atomic drivers need to instead use
         * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt().
         */
        uint32_t gamma_size;

        /**
         * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and
         * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size().
         *
         * Note that atomic drivers need to instead use
         * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt().
         */
        uint16_t *gamma_store;
        /** @helper_private: mid-layer private data */
        const struct drm_crtc_helper_funcs *helper_private;

        /** @properties: property tracking for this CRTC */
        struct drm_object_properties properties;

        /**
         * @scaling_filter_property: property to apply a particular filter while
         * scaling.
         */
        struct drm_property *scaling_filter_property;

        /**
         * @state:
         *
         * Current atomic state for this CRTC.
         *
         * This is protected by @mutex. Note that nonblocking atomic commits
         * access the current CRTC state without taking locks. Either by going
         * through the &struct drm_atomic_state pointers, see
         * for_each_oldnew_crtc_in_state(), for_each_old_crtc_in_state() and
         * for_each_new_crtc_in_state(). Or through careful ordering of atomic
         * commit operations as implemented in the atomic helpers, see
         * &struct drm_crtc_commit.
         */
        struct drm_crtc_state *state;

        /**
         * @commit_list:
         *
         * List of &drm_crtc_commit structures tracking pending commits.
         * Protected by @commit_lock. This list holds its own full reference,
         * as does the ongoing commit.
         *
         * "Note that the commit for a state change is also tracked in
         * &drm_crtc_state.commit. For accessing the immediately preceding
         * commit in an atomic update it is recommended to just use that
         * pointer in the old CRTC state, since accessing that doesn't need
         * any locking or list-walking. @commit_list should only be used to
         * stall for framebuffer cleanup that's signalled through
         * &drm_crtc_commit.cleanup_done."
         */
        struct list_head commit_list;

        /**
         * @commit_lock:
         *
         * Spinlock to protect @commit_list.
         */
        spinlock_t commit_lock;
        /**
         * @debugfs_entry:
         *
         * Debugfs directory for this CRTC.
         */
        struct dentry *debugfs_entry;

        /**
         * @crc:
         *
         * Configuration settings of CRC capture.
         */
        struct drm_crtc_crc crc;

        /**
         * @fence_context:
         *
         * timeline context used for fence operations.
         */
        unsigned int fence_context;

        /**
         * @fence_lock:
         *
         * spinlock to protect the fences in the fence_context.
         */
        spinlock_t fence_lock;
        /**
         * @fence_seqno:
         *
         * Seqno variable used as monotonic counter for the fences
         * created on the CRTC's timeline.
         */
        unsigned long fence_seqno;

        /**
         * @timeline_name:
         *
         * The name of the CRTC's fence timeline.
         */
        char timeline_name[32];

        /**
         * @self_refresh_data: Holds the state for the self refresh helpers
         *
         * Initialized via drm_self_refresh_helper_init().
         */
        struct drm_self_refresh_data *self_refresh_data;
};

该结构体包含以下成员变量:

  • dev:该crtc所属的DRM设备;
  • port:设备节点,被drm_of_find_possible_crtcs使用;
  • head:链表节点,用于将当前节点添加到&drm_mode_config.crtc_list链表;
  • name:名称,可以被驱动程序覆盖;
  • mutex:用于保护crtc状态的互斥锁;
  • basestruct drm_mode_object
  • primary:与该crtc相关的primary plane
  • cursor:与该crtc相关的cursor plane
  • index:在mode_config.list中的位置,可以用作数组索引;
  • cursor_x:光标的x坐标;
  • cursor_y:光标的y坐标;
  • enabled:指示该crtc是否已启用;
  • mode:当前模式时序信息;
  • hwmode:硬件中编程的模式;
  • x:在屏幕上的x坐标;
  • y:在屏幕上的y坐标;
  • funcscrtc控制函数;
  • gamma_size:报告给用户空间的legacy gamma ramp大小;
  • gamma_storelegacy gamma values数据存储区域;
  • helper_private:中间层私有数据;
  • properties:跟踪该crtc的属性;
  • scaling_filter_property:应用于缩放时的特定滤镜的属性;
  • state:当前crtc的原子状态;
  • commit_list:跟踪挂起提交的列表;
  • commit_lock:保护commit_list的自旋锁;
  • debugfs_entry:用于调试的目录条目;
  • crccrc捕获的配置设置;
  • fence_context:用于围栏操作的时间线上下文;
  • fence_lock:保护时间线上的围栏的自旋锁;
  • fence_seqno:用作crtc时间线上创建的围栏的单调计数器;
  • timeline_namecrtc时间线的名称;
  • self_refresh_data:保存自刷新辅助程序状态的数据;
2.1.1 struct drm_display_mode

struct drm_display_mode用于表示显示模式,包含了显示的各种时序参数配置(与显示器息息相关)。定义在include/drm/drm_modes.h

/**
 * struct drm_display_mode - DRM kernel-internal display mode structure
 * @hdisplay: horizontal display size
 * @hsync_start: horizontal sync start
 * @hsync_end: horizontal sync end
 * @htotal: horizontal total size
 * @hskew: horizontal skew?!
 * @vdisplay: vertical display size
 * @vsync_start: vertical sync start
 * @vsync_end: vertical sync end
 * @vtotal: vertical total size
 * @vscan: vertical scan?!
 * @crtc_hdisplay: hardware mode horizontal display size
 * @crtc_hblank_start: hardware mode horizontal blank start
 * @crtc_hblank_end: hardware mode horizontal blank end
 * @crtc_hsync_start: hardware mode horizontal sync start
 * @crtc_hsync_end: hardware mode horizontal sync end
 * @crtc_htotal: hardware mode horizontal total size
 * @crtc_hskew: hardware mode horizontal skew?!
 * @crtc_vdisplay: hardware mode vertical display size
 * @crtc_vblank_start: hardware mode vertical blank start
 * @crtc_vblank_end: hardware mode vertical blank end
 * @crtc_vsync_start: hardware mode vertical sync start
 * @crtc_vsync_end: hardware mode vertical sync end
 * @crtc_vtotal: hardware mode vertical total size
 *
 * This is the kernel API display mode information structure. For the
 * user-space version see struct drm_mode_modeinfo.
 *
 * The horizontal and vertical timings are defined per the following diagram.
 *
 * ::
 *
 *
 *               Active                 Front           Sync           Back
 *              Region                 Porch                          Porch
 *     <-----------------------><----------------><-------------><-------------->
 *       //////////////////////|
 *      ////////////////////// |
 *     //////////////////////  |..................               ................
 *                                                _______________
 *     <----- [hv]display ----->
 *     <------------- [hv]sync_start ------------>
 *     <--------------------- [hv]sync_end --------------------->
 *     <-------------------------------- [hv]total ----------------------------->*
 *
 * This structure contains two copies of timings. First are the plain timings,
 * which specify the logical mode, as it would be for a progressive 1:1 scanout
 * at the refresh rate userspace can observe through vblank timestamps. Then
 * there's the hardware timings, which are corrected for interlacing,
 * double-clocking and similar things. They are provided as a convenience, and
 * can be appropriately computed using drm_mode_set_crtcinfo().
 *
 * For printing you can use %DRM_MODE_FMT and DRM_MODE_ARG().
 */
struct drm_display_mode {
        /**
         * @clock:
         *
         * Pixel clock in kHz.
         */
        int clock;              /* in kHz */
        u16 hdisplay;
        u16 hsync_start;
        u16 hsync_end;
        u16 htotal;
        u16 hskew;
        u16 vdisplay;
        u16 vsync_start;
        u16 vsync_end;
        u16 vtotal;
        u16 vscan;
        /**
         * @flags:
         *
         * Sync and timing flags:
         *
         *  - DRM_MODE_FLAG_PHSYNC: horizontal sync is active high.
         *  - DRM_MODE_FLAG_NHSYNC: horizontal sync is active low.
         *  - DRM_MODE_FLAG_PVSYNC: vertical sync is active high.
         *  - DRM_MODE_FLAG_NVSYNC: vertical sync is active low.
         *  - DRM_MODE_FLAG_INTERLACE: mode is interlaced.
         *  - DRM_MODE_FLAG_DBLSCAN: mode uses doublescan.
         *  - DRM_MODE_FLAG_CSYNC: mode uses composite sync.
         *  - DRM_MODE_FLAG_PCSYNC: composite sync is active high.
         *  - DRM_MODE_FLAG_NCSYNC: composite sync is active low.
         *  - DRM_MODE_FLAG_HSKEW: hskew provided (not used?).
         *  - DRM_MODE_FLAG_BCAST: <deprecated>
         *  - DRM_MODE_FLAG_PIXMUX: <deprecated>
         *  - DRM_MODE_FLAG_DBLCLK: double-clocked mode.
         *  - DRM_MODE_FLAG_CLKDIV2: half-clocked mode.
         *
         * Additionally there's flags to specify how 3D modes are packed:
         *
         *  - DRM_MODE_FLAG_3D_NONE: normal, non-3D mode.
         *  - DRM_MODE_FLAG_3D_FRAME_PACKING: 2 full frames for left and right.
         *  - DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: interleaved like fields.
         *  - DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: interleaved lines.
         *  - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: side-by-side full frames.
         *  - DRM_MODE_FLAG_3D_L_DEPTH: ?
         *  - DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: ?
         *  - DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: frame split into top and bottom
         *    parts.
         *  - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: frame split into left and
         *    right parts.
         */
        u32 flags;
        u32 flags;

        /**
         * @crtc_clock:
         *
         * Actual pixel or dot clock in the hardware. This differs from the
         * logical @clock when e.g. using interlacing, double-clocking, stereo
         * modes or other fancy stuff that changes the timings and signals
         * actually sent over the wire.
         *
         * This is again in kHz.
         *
         * Note that with digital outputs like HDMI or DP there's usually a
         * massive confusion between the dot clock and the signal clock at the
         * bit encoding level. Especially when a 8b/10b encoding is used and the
         * difference is exactly a factor of 10.
         */
        int crtc_clock;
        u16 crtc_hdisplay;
        u16 crtc_hblank_start;
        u16 crtc_hblank_end;
        u16 crtc_hsync_start;
        u16 crtc_hsync_end;
        u16 crtc_htotal;
        u16 crtc_hskew;
        u16 crtc_vdisplay;
        u16 crtc_vblank_start;
        u16 crtc_vblank_end;
        u16 crtc_vsync_start;
        u16 crtc_vsync_end;
        u16 crtc_vtotal;

        /**
         * @width_mm:
         *
         * Addressable size of the output in mm, projectors should set this to
         * 0.
         */
        u16 width_mm;

        /**
         * @height_mm:
         *
         * Addressable size of the output in mm, projectors should set this to
         * 0.
         */
        u16 height_mm;
        /**
         * @type:
         *
         * A bitmask of flags, mostly about the source of a mode. Possible flags
         * are:
         *
         *  - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native
         *    resolution of an LCD panel. There should only be one preferred
         *    mode per connector at any given time.
         *  - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of
         *    them really. Drivers must set this bit for all modes they create
         *    and expose to userspace.
         *  - DRM_MODE_TYPE_USERDEF: Mode defined or selected via the kernel
         *    command line.
         *
         * Plus a big list of flags which shouldn't be used at all, but are
         * still around since these flags are also used in the userspace ABI.
         * We no longer accept modes with these types though:
         *
         *  - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, unused.
         *    Use DRM_MODE_TYPE_DRIVER instead.
         *  - DRM_MODE_TYPE_DEFAULT: Again a leftover, use
         *    DRM_MODE_TYPE_PREFERRED instead.
         *  - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers
         *    which are stuck around for hysterical raisins only. No one has an
         *    idea what they were meant for. Don't use.
         */
        u8 type;

        /**
         * @expose_to_userspace:
         *
         * Indicates whether the mode is to be exposed to the userspace.
         * This is to maintain a set of exposed modes while preparing
         * user-mode's list in drm_mode_getconnector ioctl. The purpose of
         * this only lies in the ioctl function, and is not to be used
         * outside the function.
         */
        bool expose_to_userspace;

        /**
         * @head:
         *
         * struct list_head for mode lists.
         */
        struct list_head head;

        /**
         * @name:
         *
         * Human-readable name of the mode, filled out with drm_mode_set_name().
         */
        char name[DRM_DISPLAY_MODE_LEN];

        /**
         * @status:
         *
         * Status of the mode, used to filter out modes not supported by the
         * hardware. See enum &drm_mode_status.
         */
        enum drm_mode_status status;
        /**
         * @picture_aspect_ratio:
         *
         * Field for setting the HDMI picture aspect ratio of a mode.
         */
        enum hdmi_picture_aspect picture_aspect_ratio;

};

结构体包含以下成员变量:

  • hdisplay:行有效像素;
  • hsync_start:行同步起始像素;
  • hsync_end:行同步结束像素;
  • htotal:行总大小;
  • hskew:行偏差,通常为 0(暂不清楚具体含义);
  • vdisplay:帧有效行;
  • vsync_start:帧同步起始行;
  • vsync_end:帧同步结束行;
  • vtotal:一帧总行数;
  • vscan: 帧扫描信号,通常为 0(暂不清楚具体含义);
  • crtc_hdisplay:硬件模式的行有效像素;;
  • crtc_hblank_start:硬件模式的行空白起始像素;
  • crtc_hblank_end:硬件模式的行空白结束像素;
  • crtc_hsync_start:硬件模式的行同步起始像素;
  • crtc_hsync_end:硬件模式的行同步结束像素;
  • crtc_htotal:硬件模式的行总大小;
  • crtc_hskew:硬件模式的行偏差,通常为 0(暂不清楚具体含义);
  • crtc_vdisplay:硬件模式的帧有效行;
  • crtc_vblank_start:硬件模式的帧空白起始行;
  • crtc_vblank_end:硬件模式的帧空白结束行;
  • crtc_vsync_start:硬件模式的帧同步起始行;
  • crtc_vsync_end:硬件模式的帧同步结束行;
  • crtc_vtotal:硬件模式的一帧总行数;

关于hdisplayhsync_starthsync_endhtotal对应着我们第一节中介绍的水平时序参数;

同理vdisplayvsync_startvsync_endvtotal对应着垂直时序参数;

2.1.2 struct drm_crtc_state

struct drm_crtc_state用于表示crtc的状态,定义在include/drm/drm_crtc.h

/**
 * struct drm_crtc_state - mutable CRTC state
 *
 * Note that the distinction between @enable and @active is rather subtle:
 * Flipping @active while @enable is set without changing anything else may
 * never return in a failure from the &drm_mode_config_funcs.atomic_check
 * callback. Userspace assumes that a DPMS On will always succeed. In other
 * words: @enable controls resource assignment, @active controls the actual
 * hardware state.
 *
 * The three booleans active_changed, connectors_changed and mode_changed are
 * intended to indicate whether a full modeset is needed, rather than strictly
 * describing what has changed in a commit. See also:
 * drm_atomic_crtc_needs_modeset()
 *
 * WARNING: Transitional helpers (like drm_helper_crtc_mode_set() or
 * drm_helper_crtc_mode_set_base()) do not maintain many of the derived control
 * state like @plane_mask so drivers not converted over to atomic helpers should
 * not rely on these being accurate!
 */
struct drm_crtc_state {
        /** @crtc: backpointer to the CRTC */
        struct drm_crtc *crtc;

        /**
         * @enable: Whether the CRTC should be enabled, gates all other state.
         * This controls reservations of shared resources. Actual hardware state
         * is controlled by @active.
         */
        bool enable;

        /**
         * @active: Whether the CRTC is actively displaying (used for DPMS).
         * Implies that @enable is set. The driver must not release any shared
         * resources if @active is set to false but @enable still true, because
         * userspace expects that a DPMS ON always succeeds.
         *
         * Hence drivers must not consult @active in their various
         * &drm_mode_config_funcs.atomic_check callback to reject an atomic
         * commit. They can consult it to aid in the computation of derived
         * hardware state, since even in the DPMS OFF state the display hardware
         * should be as much powered down as when the CRTC is completely
         * disabled through setting @enable to false.
         */
        bool active;

        /**
         * @planes_changed: Planes on this crtc are updated. Used by the atomic
         * helpers and drivers to steer the atomic commit control flow.
         */
        bool planes_changed : 1;

        /**
         * @mode_changed: @mode or @enable has been changed. Used by the atomic
         * helpers and drivers to steer the atomic commit control flow. See also
         * drm_atomic_crtc_needs_modeset().
         *
         * Drivers are supposed to set this for any CRTC state changes that
         * require a full modeset. They can also reset it to false if e.g. a
         * @mode change can be done without a full modeset by only changing
         * scaler settings.
         */
        bool mode_changed : 1;
        /**
         * @active_changed: @active has been toggled. Used by the atomic
         * helpers and drivers to steer the atomic commit control flow. See also
         * drm_atomic_crtc_needs_modeset().
         */
        bool active_changed : 1;

        /**
         * @connectors_changed: Connectors to this crtc have been updated,
         * either in their state or routing. Used by the atomic
         * helpers and drivers to steer the atomic commit control flow. See also
         * drm_atomic_crtc_needs_modeset().
         *
         * Drivers are supposed to set this as-needed from their own atomic
         * check code, e.g. from &drm_encoder_helper_funcs.atomic_check
         */
        bool connectors_changed : 1;
 
 		/**
         * @zpos_changed: zpos values of planes on this crtc have been updated.
         * Used by the atomic helpers and drivers to steer the atomic commit
         * control flow.
         */
        bool zpos_changed : 1;
        /**
         * @color_mgmt_changed: Color management properties have changed
         * (@gamma_lut, @degamma_lut or @ctm). Used by the atomic helpers and
         * drivers to steer the atomic commit control flow.
         */
        bool color_mgmt_changed : 1;

        /**
         * @no_vblank:
         *
         * Reflects the ability of a CRTC to send VBLANK events. This state
         * usually depends on the pipeline configuration. If set to true, DRM
         * atomic helpers will send out a fake VBLANK event during display
         * updates after all hardware changes have been committed. This is
         * implemented in drm_atomic_helper_fake_vblank().
         *
         * One usage is for drivers and/or hardware without support for VBLANK
         * interrupts. Such drivers typically do not initialize vblanking
         * (i.e., call drm_vblank_init() with the number of CRTCs). For CRTCs
         * without initialized vblanking, this field is set to true in
         * drm_atomic_helper_check_modeset(), and a fake VBLANK event will be
         * send out on each update of the display pipeline by
         * drm_atomic_helper_fake_vblank().
         *
         * Another usage is CRTCs feeding a writeback connector operating in
         * oneshot mode. In this case the fake VBLANK event is only generated
         * when a job is queued to the writeback connector, and we want the
         * core to fake VBLANK events when this part of the pipeline hasn't
         * changed but others had or when the CRTC and connectors are being
         * disabled.
         *
         * __drm_atomic_helper_crtc_duplicate_state() will not reset the value
         * from the current state, the CRTC driver is then responsible for
         * updating this field when needed.
         *
         * Note that the combination of &drm_crtc_state.event == NULL and
         * &drm_crtc_state.no_blank == true is valid and usually used when the
         * writeback connector attached to the CRTC has a new job queued. In
         * this case the driver will send the VBLANK event on its own when the
         * writeback job is complete.
        bool no_vblank : 1;

        /**
         * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to
         * this CRTC.
         */
        u32 plane_mask;

        /**
         * @connector_mask: Bitmask of drm_connector_mask(connector) of
         * connectors attached to this CRTC.
         */
        u32 connector_mask;

        /**
         * @encoder_mask: Bitmask of drm_encoder_mask(encoder) of encoders
         * attached to this CRTC.
         */
        u32 encoder_mask;

        /**
         * @adjusted_mode:
         *
         * Internal display timings which can be used by the driver to handle
         * differences between the mode requested by userspace in @mode and what
         * is actually programmed into the hardware.
         *
         * For drivers using &drm_bridge, this stores hardware display timings
         * used between the CRTC and the first bridge. For other drivers, the
         * meaning of the adjusted_mode field is purely driver implementation
         * defined information, and will usually be used to store the hardware
         * display timings used between the CRTC and encoder blocks.
         */
        struct drm_display_mode adjusted_mode;

        /**
         * @mode:
         *
         * Display timings requested by userspace. The driver should try to
         * match the refresh rate as close as possible (but note that it's
         * undefined what exactly is close enough, e.g. some of the HDMI modes
         * only differ in less than 1% of the refresh rate). The active width
         * and height as observed by userspace for positioning planes must match
         * exactly.
         *
         * For external connectors where the sink isn't fixed (like with a
         * built-in panel), this mode here should match the physical mode on the
         * wire to the last details (i.e. including sync polarities and
         * everything).
         */
        struct drm_display_mode mode;

        /**
         * @mode_blob: &drm_property_blob for @mode, for exposing the mode to
         * atomic userspace.
         */
        struct drm_property_blob *mode_blob;

        /**
         * @degamma_lut:
         *
         * Lookup table for converting framebuffer pixel data before apply the
         * color conversion matrix @ctm. See drm_crtc_enable_color_mgmt(). The
         * blob (if not NULL) is an array of &struct drm_color_lut.
         */
        struct drm_property_blob *degamma_lut;

        /**
         * @ctm:
         *
         * Color transformation matrix. See drm_crtc_enable_color_mgmt(). The
         * blob (if not NULL) is a &struct drm_color_ctm.
         */
        struct drm_property_blob *ctm;

        /**
         * @gamma_lut:
         *
         * Lookup table for converting pixel data after the color conversion
         * matrix @ctm.  See drm_crtc_enable_color_mgmt(). The blob (if not
         * NULL) is an array of &struct drm_color_lut.
         *
         * Note that for mostly historical reasons stemming from Xorg heritage,
         * this is also used to store the color map (also sometimes color lut,
         * CLUT or color palette) for indexed formats like DRM_FORMAT_C8.
         */
        struct drm_property_blob *gamma_lut;

        /**
         * @target_vblank:
         *
         * Target vertical blank period when a page flip
         * should take effect.
         */
        u32 target_vblank;

        /**
         * @async_flip:
         *
         * This is set when DRM_MODE_PAGE_FLIP_ASYNC is set in the legacy
         * PAGE_FLIP IOCTL. It's not wired up for the atomic IOCTL itself yet.
         */
        bool async_flip;

        /**
         * @vrr_enabled:
         *
         * Indicates if variable refresh rate should be enabled for the CRTC.
         * Support for the requested vrr state will depend on driver and
         * hardware capabiltiy - lacking support is not treated as failure.
         */
        bool vrr_enabled;

        /**
         * @self_refresh_active:
         *
         * Used by the self refresh helpers to denote when a self refresh
         * transition is occurring. This will be set on enable/disable callbacks
         * when self refresh is being enabled or disabled. In some cases, it may
         * not be desirable to fully shut off the crtc during self refresh.
         * CRTC's can inspect this flag and determine the best course of action.
         */
        bool self_refresh_active;

        /**
         * @scaling_filter:
         *
         * Scaling filter to be applied
         */
        enum drm_scaling_filter scaling_filter;

        /**
         * @event:
         *
         * Optional pointer to a DRM event to signal upon completion of the
         * state update. The driver must send out the event when the atomic
         * commit operation completes. There are two cases:
         *
         *  - The event is for a CRTC which is being disabled through this
         *    atomic commit. In that case the event can be send out any time
         *    after the hardware has stopped scanning out the current
         *    framebuffers. It should contain the timestamp and counter for the
         *    last vblank before the display pipeline was shut off. The simplest
         *    way to achieve that is calling drm_crtc_send_vblank_event()
         *    somewhen after drm_crtc_vblank_off() has been called.
         *
         *  - For a CRTC which is enabled at the end of the commit (even when it
         *    undergoes an full modeset) the vblank timestamp and counter must
         *    be for the vblank right before the first frame that scans out the
         *    new set of buffers. Again the event can only be sent out after the
         *    hardware has stopped scanning out the old buffers.
         *
         *  - Events for disabled CRTCs are not allowed, and drivers can ignore
         *    that case.
         *
         * For very simple hardware without VBLANK interrupt, enabling
         * &struct drm_crtc_state.no_vblank makes DRM's atomic commit helpers
         * send a fake VBLANK event at the end of the display update after all
         * hardware changes have been applied. See
         * drm_atomic_helper_fake_vblank().
         *
         * For more complex hardware this
         * can be handled by the drm_crtc_send_vblank_event() function,
         * which the driver should call on the provided event upon completion of
         * the atomic commit. Note that if the driver supports vblank signalling
         * and timestamping the vblank counters and timestamps must agree with
         * the ones returned from page flip events. With the current vblank
         * helper infrastructure this can be achieved by holding a vblank
         * reference while the page flip is pending, acquired through
         * drm_crtc_vblank_get() and released with drm_crtc_vblank_put().
         * Drivers are free to implement their own vblank counter and timestamp
         * tracking though, e.g. if they have accurate timestamp registers in
         * hardware.
         *
         * For hardware which supports some means to synchronize vblank

         * interrupt delivery with committing display state there's also
         * drm_crtc_arm_vblank_event(). See the documentation of that function
         * for a detailed discussion of the constraints it needs to be used
         * safely.
         *
         * If the device can't notify of flip completion in a race-free way
         * at all, then the event should be armed just after the page flip is
         * committed. In the worst case the driver will send the event to
         * userspace one frame too late. This doesn't allow for a real atomic
         * update, but it should avoid tearing.
         */
        struct drm_pending_vblank_event *event;

        /**
         * @commit:
         *
         * This tracks how the commit for this update proceeds through the
         * various phases. This is never cleared, except when we destroy the
         * state, so that subsequent commits can synchronize with previous ones.
         */
        struct drm_crtc_commit *commit;

        /** @state: backpointer to global drm_atomic_state */
        struct drm_atomic_state *state;
};

2.2 操作函数

2.2.1 struct drm_crtc_funcs

struct drm_crtc_funcs用于定义与crtc相关的函数和操作,该结构体包含了一系列函数指针,用于实现包括模式设置、帧缓冲区映射、显示控制等功能。定义在include/drm/drm_crtc.h

/**
 * struct drm_crtc_funcs - control CRTCs for a given device
 *
 * The drm_crtc_funcs structure is the central CRTC management structure
 * in the DRM.  Each CRTC controls one or more connectors (note that the name
 * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
 * connectors, not just CRTs).
 *
 * Each driver is responsible for filling out this structure at startup time,
 * in addition to providing other modesetting features, like i2c and DDC
 * bus accessors.
 */
struct drm_crtc_funcs {
        /**
         * @reset:
         *
         * Reset CRTC hardware and software state to off. This function isn't
         * called by the core directly, only through drm_mode_config_reset().
         * It's not a helper hook only for historical reasons.
         *
         * Atomic drivers can use drm_atomic_helper_crtc_reset() to reset
         * atomic state using this hook.
         */
        void (*reset)(struct drm_crtc *crtc);

        /**
         * @cursor_set:
         *
         * Update the cursor image. The cursor position is relative to the CRTC
         * and can be partially or fully outside of the visible area.
         *
         * Note that contrary to all other KMS functions the legacy cursor entry
         * points don't take a framebuffer object, but instead take directly a
         * raw buffer object id from the driver's buffer manager (which is
         * either GEM or TTM for current drivers).
         *
         * This entry point is deprecated, drivers should instead implement
         * universal plane support and register a proper cursor plane using
         * drm_crtc_init_with_planes().
         *
         * This callback is optional
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
                          uint32_t handle, uint32_t width, uint32_t height);

        /**
         * @cursor_set2:
         *
         * Update the cursor image, including hotspot information. The hotspot
         * must not affect the cursor position in CRTC coordinates, but is only
         * meant as a hint for virtualized display hardware to coordinate the
         * guests and hosts cursor position. The cursor hotspot is relative to
         * the cursor image. Otherwise this works exactly like @cursor_set.
         *
         * This entry point is deprecated, drivers should instead implement
         * universal plane support and register a proper cursor plane using
         * drm_crtc_init_with_planes().
         *
         * This callback is optional.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,
                           uint32_t handle, uint32_t width, uint32_t height,
                           int32_t hot_x, int32_t hot_y);

        /**
         * @cursor_move:
         *
         * Update the cursor position. The cursor does not need to be visible
         * when this hook is called.
         *
         * This entry point is deprecated, drivers should instead implement
         * universal plane support and register a proper cursor plane using
         * drm_crtc_init_with_planes().
         *
         * This callback is optional.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*cursor_move)(struct drm_crtc *crtc, int x, int y);

        /**
         * @gamma_set:
         *
         * Set gamma on the CRTC.
         *
         * This callback is optional.
         *
         * Atomic drivers who want to support gamma tables should implement the
         * atomic color management support, enabled by calling
         * drm_crtc_enable_color_mgmt(), which then supports the legacy gamma
         * interface through the drm_atomic_helper_legacy_gamma_set()
         * compatibility implementation.
         */
        int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
                         uint32_t size,
                         struct drm_modeset_acquire_ctx *ctx);

        /**
         * @destroy:
         *
         * Clean up CRTC resources. This is only called at driver unload time
         * through drm_mode_config_cleanup() since a CRTC cannot be hotplugged
         * in DRM.
         */
        void (*destroy)(struct drm_crtc *crtc);

        /**
         * @set_config:
         *
         * This is the main legacy entry point to change the modeset state on a
         * CRTC. All the details of the desired configuration are passed in a
         * &struct drm_mode_set - see there for details.
         *
         * Drivers implementing atomic modeset should use
         * drm_atomic_helper_set_config() to implement this hook.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*set_config)(struct drm_mode_set *set,
                          struct drm_modeset_acquire_ctx *ctx);
        /**
         * @page_flip:
         *
         * Legacy entry point to schedule a flip to the given framebuffer.
         *
         * Page flipping is a synchronization mechanism that replaces the frame
         * buffer being scanned out by the CRTC with a new frame buffer during
         * vertical blanking, avoiding tearing (except when requested otherwise
         * through the DRM_MODE_PAGE_FLIP_ASYNC flag). When an application
         * requests a page flip the DRM core verifies that the new frame buffer
         * is large enough to be scanned out by the CRTC in the currently
         * configured mode and then calls this hook with a pointer to the new
         * frame buffer.
         *
         * The driver must wait for any pending rendering to the new framebuffer
         * to complete before executing the flip. It should also wait for any
         * pending rendering from other drivers if the underlying buffer is a
         * shared dma-buf.
         *
         * An application can request to be notified when the page flip has
         * completed. The drm core will supply a &struct drm_event in the event
         * parameter in this case. This can be handled by the
         * drm_crtc_send_vblank_event() function, which the driver should call on
         * the provided event upon completion of the flip. Note that if
         * the driver supports vblank signalling and timestamping the vblank
         * counters and timestamps must agree with the ones returned from page
         * flip events. With the current vblank helper infrastructure this can
         * be achieved by holding a vblank reference while the page flip is
         * pending, acquired through drm_crtc_vblank_get() and released with
         * drm_crtc_vblank_put(). Drivers are free to implement their own vblank
         * counter and timestamp tracking though, e.g. if they have accurate
         * timestamp registers in hardware.
         *
         * This callback is optional.
         *
         * NOTE:
         *
         * Very early versions of the KMS ABI mandated that the driver must
         * block (but not reject) any rendering to the old framebuffer until the
         * flip operation has completed and the old framebuffer is no longer
         * visible. This requirement has been lifted, and userspace is instead
         * expected to request delivery of an event and wait with recycling old
         * buffers until such has been received.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure. Note that if a
         * page flip operation is already pending the callback should return
         * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode
         * or just runtime disabled through DPMS respectively the new atomic
         * "ACTIVE" state) should result in an -EINVAL error code. Note that
         * drm_atomic_helper_page_flip() checks this already for atomic drivers.
         */
        int (*page_flip)(struct drm_crtc *crtc,
                         struct drm_framebuffer *fb,
                         struct drm_pending_vblank_event *event,
                         uint32_t flags,
                         struct drm_modeset_acquire_ctx *ctx);

        /**
         * @page_flip_target:
         *
         * Same as @page_flip but with an additional parameter specifying the
         * absolute target vertical blank period (as reported by
         * drm_crtc_vblank_count()) when the flip should take effect.
         *
         * Note that the core code calls drm_crtc_vblank_get before this entry
         * point, and will call drm_crtc_vblank_put if this entry point returns
         * any non-0 error code. It's the driver's responsibility to call
         * drm_crtc_vblank_put after this entry point returns 0, typically when
         * the flip completes.
         */
        int (*page_flip_target)(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
                                uint32_t flags, uint32_t target,
                                struct drm_modeset_acquire_ctx *ctx);

        /**
         * @set_property:
         *
         * This is the legacy entry point to update a property attached to the
         * CRTC.
         *
         * This callback is optional if the driver does not support any legacy
         * driver-private properties. For atomic drivers it is not used because
         * property handling is done entirely in the DRM core.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*set_property)(struct drm_crtc *crtc,
                            struct drm_property *property, uint64_t val);

        /**
         * @atomic_duplicate_state:
         *
         * Duplicate the current atomic state for this CRTC and return it.
         * The core and helpers guarantee that any atomic state duplicated with
         * this hook and still owned by the caller (i.e. not transferred to the
         * driver by calling &drm_mode_config_funcs.atomic_commit) will be
         * cleaned up by calling the @atomic_destroy_state hook in this
         * structure.
         *
         * This callback is mandatory for atomic drivers.
         *
         * Atomic drivers which don't subclass &struct drm_crtc_state should use
         * drm_atomic_helper_crtc_duplicate_state(). Drivers that subclass the
         * state structure to extend it with driver-private state should use
         * __drm_atomic_helper_crtc_duplicate_state() to make sure shared state is
         * duplicated in a consistent fashion across drivers.
         *
         * It is an error to call this hook before &drm_crtc.state has been
         * initialized correctly.
         *
         * NOTE:
         *
         * If the duplicate state references refcounted resources this hook must
         * acquire a reference for each of them. The driver must release these
         * references again in @atomic_destroy_state.
         *
         * RETURNS:
         *
         * Duplicated atomic state or NULL when the allocation failed.
         */
        struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);

        /**
         * @atomic_destroy_state:
         *
         * Destroy a state duplicated with @atomic_duplicate_state and release
         * or unreference all resources it references
         *
         * This callback is mandatory for atomic drivers.
         */
        void (*atomic_destroy_state)(struct drm_crtc *crtc,
                                     struct drm_crtc_state *state);

        /**
         * @atomic_set_property:
         *
         * Decode a driver-private property value and store the decoded value
         * into the passed-in state structure. Since the atomic core decodes all
         * standardized properties (even for extensions beyond the core set of
         * properties which might not be implemented by all drivers) this
         * requires drivers to subclass the state structure.
         *
         * Such driver-private properties should really only be implemented for
         * truly hardware/vendor specific state. Instead it is preferred to
         * standardize atomic extension and decode the properties used to expose
         * such an extension in the core.
         *
         * Do not call this function directly, use
         * drm_atomic_crtc_set_property() instead.
         *
         * This callback is optional if the driver does not support any
         * driver-private atomic properties.
         *
         * NOTE:
         *
         * This function is called in the state assembly phase of atomic
         * modesets, which can be aborted for any reason (including on
         * userspace's request to just check whether a configuration would be
         * possible). Drivers MUST NOT touch any persistent state (hardware or
         * software) or data structures except the passed in @state parameter.
         *
         * Also since userspace controls in which order properties are set this
         * function must not do any input validation (since the state update is
         * incomplete and hence likely inconsistent). Instead any such input
         * validation must be done in the various atomic_check callbacks.
         *
         * RETURNS:
         *
         * 0 if the property has been found, -EINVAL if the property isn't
         * implemented by the driver (which should never happen, the core only
         * asks for properties attached to this CRTC). No other validation is
         * allowed by the driver. The core already checks that the property
         * value is within the range (integer, valid enum value, ...) the driver
         * set when registering the property.
         */
        int (*atomic_set_property)(struct drm_crtc *crtc,
                                   struct drm_crtc_state *state,
                                   struct drm_property *property,
                                   uint64_t val);
        /**
         * @atomic_get_property:
         *
         * Reads out the decoded driver-private property. This is used to
         * implement the GETCRTC IOCTL.
         *
         * Do not call this function directly, use
         * drm_atomic_crtc_get_property() instead.
         *
         * This callback is optional if the driver does not support any
         * driver-private atomic properties.
         *
         * RETURNS:
         *
         * 0 on success, -EINVAL if the property isn't implemented by the
         * driver (which should never happen, the core only asks for
         * properties attached to this CRTC).
         */
        int (*atomic_get_property)(struct drm_crtc *crtc,
                                   const struct drm_crtc_state *state,
                                   struct drm_property *property,
                                   uint64_t *val);

        /**
         * @late_register:
         *
         * This optional hook can be used to register additional userspace
         * interfaces attached to the crtc like debugfs interfaces.
         * It is called late in the driver load sequence from drm_dev_register().
         * Everything added from this callback should be unregistered in
         * the early_unregister callback.
         *
         * Returns:
         *
         * 0 on success, or a negative error code on failure.
         */
        int (*late_register)(struct drm_crtc *crtc);

        /**
         * @early_unregister:
         *
         * This optional hook should be used to unregister the additional
         * userspace interfaces attached to the crtc from
         * @late_register. It is called from drm_dev_unregister(),
         * early in the driver unload sequence to disable userspace access
         * before data structures are torndown.
         */
        void (*early_unregister)(struct drm_crtc *crtc);

        /**
         * @set_crc_source:
         *
         * Changes the source of CRC checksums of frames at the request of
         * userspace, typically for testing purposes. The sources available are
         * specific of each driver and a %NULL value indicates that CRC
         * generation is to be switched off.
         *
         * When CRC generation is enabled, the driver should call
         * drm_crtc_add_crc_entry() at each frame, providing any information
         * that characterizes the frame contents in the crcN arguments, as
         * provided from the configured source. Drivers must accept an "auto"
         * source name that will select a default source for this CRTC.
         *
         * This may trigger an atomic modeset commit if necessary, to enable CRC
         * generation.
         *
         * Note that "auto" can depend upon the current modeset configuration,
         * e.g. it could pick an encoder or output specific CRC sampling point.
         *
         * This callback is optional if the driver does not support any CRC
         * generation functionality.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*set_crc_source)(struct drm_crtc *crtc, const char *source);

        /**
         * @verify_crc_source:
         *
         * verifies the source of CRC checksums of frames before setting the
         * source for CRC and during crc open. Source parameter can be NULL
         * while disabling crc source.
         *
         * This callback is optional if the driver does not support any CRC
         * generation functionality.
         *
         * RETURNS:
         *
         * 0 on success or a negative error code on failure.
         */
        int (*verify_crc_source)(struct drm_crtc *crtc, const char *source,
                                 size_t *values_cnt);
        /**
         * @get_crc_sources:
         *
         * Driver callback for getting a list of all the available sources for
         * CRC generation. This callback depends upon verify_crc_source, So
         * verify_crc_source callback should be implemented before implementing
         * this. Driver can pass full list of available crc sources, this
         * callback does the verification on each crc-source before passing it
         * to userspace.
         *
         * This callback is optional if the driver does not support exporting of
         * possible CRC sources list.
         *
         * RETURNS:
         *
         * a constant character pointer to the list of all the available CRC
         * sources. On failure driver should return NULL. count should be
         * updated with number of sources in list. if zero we don't process any
         * source from the list.
         */
        const char *const *(*get_crc_sources)(struct drm_crtc *crtc,
                                              size_t *count);

        /**
         * @atomic_print_state:
         *
         * If driver subclasses &struct drm_crtc_state, it should implement
         * this optional hook for printing additional driver specific state.
         *
         * Do not call this directly, use drm_atomic_crtc_print_state()
         * instead.
         */
        void (*atomic_print_state)(struct drm_printer *p,
                                   const struct drm_crtc_state *state);

        /**
         * @get_vblank_counter:
         *
         * Driver callback for fetching a raw hardware vblank counter for the
         * CRTC. It's meant to be used by new drivers as the replacement of
         * &drm_driver.get_vblank_counter hook.
         *
         * This callback is optional. If a device doesn't have a hardware
         * counter, the driver can simply leave the hook as NULL. The DRM core
         * will account for missed vblank events while interrupts where disabled
         * based on system timestamps.
         *
         * Wraparound handling and loss of events due to modesetting is dealt
         * with in the DRM core code, as long as drivers call
         * drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or
         * enabling a CRTC.
         *
         * See also &drm_device.vblank_disable_immediate and
         * &drm_device.max_vblank_count.
         *
         * Returns:
         *
         * Raw vblank counter value.
         */
        u32 (*get_vblank_counter)(struct drm_crtc *crtc);

        /**
         * @enable_vblank:
         *
         * Enable vblank interrupts for the CRTC. It's meant to be used by
         * new drivers as the replacement of &drm_driver.enable_vblank hook.
         *
         * Returns:
         *
         * Zero on success, appropriate errno if the vblank interrupt cannot
         * be enabled.
         */
        int (*enable_vblank)(struct drm_crtc *crtc);

        /**
         * @disable_vblank:
         *
         * Disable vblank interrupts for the CRTC. It's meant to be used by
         * new drivers as the replacement of &drm_driver.disable_vblank hook.
         */
        void (*disable_vblank)(struct drm_crtc *crtc);

        /**
         * @get_vblank_timestamp:
         *
         * Called by drm_get_last_vbltimestamp(). Should return a precise
         * timestamp when the most recent vblank interval ended or will end.
         *
         * Specifically, the timestamp in @vblank_time should correspond as
         * closely as possible to the time when the first video scanline of
         * the video frame after the end of vblank will start scanning out,
         * the time immediately after end of the vblank interval. If the
         * @crtc is currently inside vblank, this will be a time in the future.
         * If the @crtc is currently scanning out a frame, this will be the
         * past start time of the current scanout. This is meant to adhere
         * to the OpenML OML_sync_control extension specification.
         *
         * Parameters:
         *
         * crtc:
         *     CRTC for which timestamp should be returned.
         * max_error:
         *     Maximum allowable timestamp error in nanoseconds.
         *     Implementation should strive to provide timestamp
         *     with an error of at most max_error nanoseconds.
         *     Returns true upper bound on error for timestamp.
         * vblank_time:
         *     Target location for returned vblank timestamp.
         * in_vblank_irq:
         *     True when called from drm_crtc_handle_vblank().  Some drivers
         *     need to apply some workarounds for gpu-specific vblank irq quirks
         *     if flag is set.
         *
         * Returns:
         *
         * True on success, false on failure, which means the core should
         * fallback to a simple timestamp taken in drm_crtc_handle_vblank().
         */
        bool (*get_vblank_timestamp)(struct drm_crtc *crtc,
                                     int *max_error,
                                     ktime_t *vblank_time,
                                     bool in_vblank_irq);
};

这里定义了一大堆回调函数:

  • reset:用于将crtc硬件和软件重置为关闭状态,这个函数不会直接调用,只会通过drm_mode_config_reset调用;

  • cursor_set:更新光标图像,光标位置是相对于crtc,并且可以部分或完全位于可见区域之外;

  • cursor_set2:更新光标图像,包括热点信息;

  • cursor_move:更新光标位置。在调用此钩子时,光标不需要可见;

  • gamma_set:在crtc上设置gamma

  • destroy:清理crtc资源;

  • set_config:改变modeset state, 负责配置几个内容:

    • 更新正在扫描的framebuffer
    • 配置显示模式:时序、分辨率等;
    • 将连接器/编码器附加到crtc
  • page_flip:用于反转给定的framebuffer

  • ...

2.2.2 struct drm_crtc_helper_funcs

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(1751)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示