AMDgpu 显示管理器

AMDgpu 显示管理器,amdgpu_dm(或更简单的 dm)位于 DRM 和 DC 之间。它充当联络员,将 DRM 请求转换为 DC 请求,并将 DC 响应转换为 DRM 响应。

根控制结构是 struct amdgpu_display_manager

struct dm_compressor_info

帧缓冲区压缩使用的缓冲区信息

定义:

struct dm_compressor_info {
    void *cpu_addr;
    struct amdgpu_bo *bo_ptr;
    uint64_t gpu_addr;
};

成员

cpu_addr

MMIO CPU 地址

bo_ptr

指向缓冲区对象的指针

gpu_addr

MMIO GPU 地址

struct dmub_hpd_work

在低优先级出站箱 IRQ 中处理耗时的工作

定义:

struct dmub_hpd_work {
    struct work_struct handle_hpd_work;
    struct dmub_notification *dmub_notify;
    struct amdgpu_device *adev;
};

成员

handle_hpd_work

要在单独的线程中执行以处理 hpd_low_irq 的工作

dmub_notify

回调函数的通知

adev

amdgpu_device 指针

struct vblank_control_work

垂直消隐控制的工作数据

定义:

struct vblank_control_work {
    struct work_struct work;
    struct amdgpu_display_manager *dm;
    struct amdgpu_crtc *acrtc;
    struct dc_stream_state *stream;
    bool enable;
};

成员

work

工作事件的内核工作数据

dm

amdgpu 显示管理器设备

acrtc

发生事件的 amdgpu CRTC 实例

stream

发生事件的 DC 流

enable

如果启用垂直消隐,则为 true

struct idle_workqueue

空闲时定期操作的工作数据

定义:

struct idle_workqueue {
    struct work_struct work;
    struct amdgpu_display_manager *dm;
    bool enable;
    bool running;
};

成员

work

工作事件的内核工作数据

dm

amdgpu 显示管理器设备

enable

如果启用空闲工作程序,则为 true

running

如果空闲工作程序正在运行,则为 true

struct amdgpu_dm_luminance_data

自定义亮度数据

定义:

struct amdgpu_dm_luminance_data {
    u8 luminance;
    u8 input_signal;
};

成员

luminance

以百分比表示的亮度

input_signal

范围 0-255 中的输入信号

struct amdgpu_dm_backlight_caps

关于背光的信息

定义:

struct amdgpu_dm_backlight_caps {
    union dpcd_sink_ext_caps *ext_caps;
    u32 aux_min_input_signal;
    u32 aux_max_input_signal;
    int min_input_signal;
    int max_input_signal;
    bool caps_valid;
    bool aux_support;
    u8 ac_level;
    u8 dc_level;
    u8 data_points;
    struct amdgpu_dm_luminance_data luminance_data[MAX_LUMINANCE_DATA_POINTS];
};

成员

ext_caps

保留具有有关 HDR 显示器支持的所有信息的数据结构。

aux_min_input_signal

显示器支持的最小亮度值

aux_max_input_signal

显示器支持的最大亮度值(以尼特为单位)。

min_input_signal

范围 0-255 中的最小可能输入。

max_input_signal

范围 0-255 中的最大可能输入。

caps_valid

如果这些值来自 ACPI 接口,则为 true。

aux_support

描述显示器是否支持 AUX 背光。

ac_level

如果引导至交流电源,则为默认亮度

dc_level

如果引导至直流电源,则为默认亮度

data_points

自定义亮度数据点的数量

luminance_data

自定义亮度数据

描述

描述 ACPI 或 eDP AUX 的背光支持。

struct dal_allocation

跟踪为 SMU 通信映射的 FB 内存

定义:

struct dal_allocation {
    struct list_head list;
    struct amdgpu_bo *bo;
    void *cpu_ptr;
    u64 gpu_addr;
};

成员

list

dal 分配列表

bo

GPU 缓冲区对象

cpu_ptr

GPU 缓冲区对象的 CPU 虚拟地址

gpu_addr

GPU 缓冲区对象的 GPU 虚拟地址

struct hpd_rx_irq_offload_work_queue

工作队列以处理 hpd_rx_irq 卸载工作

定义:

struct hpd_rx_irq_offload_work_queue {
    struct workqueue_struct *wq;
    spinlock_t offload_lock;
    bool is_handling_link_loss;
    bool is_handling_mst_msg_rdy_event;
    struct amdgpu_dm_connector *aconnector;
};

成员

wq

将卸载工作排队的工作队列结构。

offload_lock

用于保护卸载工作队列的字段。

is_handling_link_loss

用于防止在我们处理链路丢失时插入链路丢失事件

is_handling_mst_msg_rdy_event

用于防止在我们已经处理 mst 消息就绪事件时插入 mst 消息就绪事件

aconnector

此工作队列所连接到的 aconnector

struct hpd_rx_irq_offload_work

hpd_rx_irq 卸载工作结构

定义:

struct hpd_rx_irq_offload_work {
    struct work_struct work;
    union hpd_irq_data data;
    struct hpd_rx_irq_offload_work_queue *offload_wq;
    struct amdgpu_device *adev;
};

成员

work

卸载工作

data

在处理卸载工作时使用的参考 irq 数据

offload_wq

此工作排队到的卸载工作队列

adev

amdgpu_device 指针

struct amdgpu_display_manager

中央 amdgpu 显示管理器设备

定义:

struct amdgpu_display_manager {
    struct dc *dc;
    struct dmub_srv *dmub_srv;
    struct dmub_notification *dmub_notify;
    dmub_notify_interrupt_callback_t dmub_callback[AMDGPU_DMUB_NOTIFICATION_MAX];
    bool dmub_thread_offload[AMDGPU_DMUB_NOTIFICATION_MAX];
    struct dmub_srv_fb_info *dmub_fb_info;
    const struct firmware *dmub_fw;
    struct amdgpu_bo *dmub_bo;
    u64 dmub_bo_gpu_addr;
    void *dmub_bo_cpu_addr;
    uint32_t dmcub_fw_version;
    struct cgs_device *cgs_device;
    struct amdgpu_device *adev;
    struct drm_device *ddev;
    u16 display_indexes_num;
    struct drm_private_obj atomic_obj;
    struct mutex dc_lock;
    struct mutex audio_lock;
    struct drm_audio_component *audio_component;
    bool audio_registered;
    struct list_head irq_handler_list_low_tab[DAL_IRQ_SOURCES_NUMBER];
    struct list_head irq_handler_list_high_tab[DAL_IRQ_SOURCES_NUMBER];
    struct common_irq_params pflip_params[DC_IRQ_SOURCE_PFLIP_LAST - DC_IRQ_SOURCE_PFLIP_FIRST + 1];
    struct common_irq_params vblank_params[DC_IRQ_SOURCE_VBLANK6 - DC_IRQ_SOURCE_VBLANK1 + 1];
    struct common_irq_params vline0_params[DC_IRQ_SOURCE_DC6_VLINE0 - DC_IRQ_SOURCE_DC1_VLINE0 + 1];
    struct common_irq_params vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
    struct common_irq_params dmub_trace_params[1];
    struct common_irq_params dmub_outbox_params[1];
    spinlock_t irq_handler_list_table_lock;
    struct backlight_device *backlight_dev[AMDGPU_DM_MAX_NUM_EDP];
    const struct dc_link *backlight_link[AMDGPU_DM_MAX_NUM_EDP];
    uint8_t num_of_edps;
    struct amdgpu_dm_backlight_caps backlight_caps[AMDGPU_DM_MAX_NUM_EDP];
    struct mod_freesync *freesync_module;
    struct hdcp_workqueue *hdcp_workqueue;
    struct workqueue_struct *vblank_control_workqueue;
    struct idle_workqueue *idle_workqueue;
    struct drm_atomic_state *cached_state;
    struct dc_state *cached_dc_state;
    struct dm_compressor_info compressor;
    const struct firmware *fw_dmcu;
    uint32_t dmcu_fw_version;
    const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box;
    uint32_t active_vblank_irq_count;
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY);
    struct secure_display_context secure_display_ctx;
#endif;
    struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq;
    struct amdgpu_encoder mst_encoders[AMDGPU_DM_MAX_CRTC];
    bool force_timing_sync;
    bool disable_hpd_irq;
    bool dmcub_trace_event_en;
    struct list_head da_list;
    struct completion dmub_aux_transfer_done;
    struct workqueue_struct *delayed_hpd_wq;
    u32 brightness[AMDGPU_DM_MAX_NUM_EDP];
    u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
    bool aux_hpd_discon_quirk;
    bool edp0_on_dp1_quirk;
    struct mutex dpia_aux_lock;
    struct dml2_soc_bb *bb_from_dmub;
    struct amdgpu_i2c_adapter *oem_i2c;
    struct fused_io_sync {
        struct completion replied;
        char reply_data[0x40];
    } fused_io[8];
};

成员

dc

显示核心控制结构

dmub_srv

DMUB 服务,用于控制支持它的硬件上的 DMUB。在不支持它的硬件上,指向 dmub_srv 的指针将为 NULL。

dmub_notify

来自 DMUB 的通知。

dmub_callback

用于处理来自 DMUB 的通知的回调函数。

dmub_thread_offload

指示回调是否卸载的标志。

dmub_fb_info

DMUB 的帧缓冲区区域。

dmub_fw

DMUB 固件,在具有 DMUB 支持的硬件上是必需的。

dmub_bo

DMUB 的缓冲区对象。

dmub_bo_gpu_addr

DMUB 缓冲区对象的 GPU 虚拟地址。

dmub_bo_cpu_addr

DMUB 缓冲区对象的 CPU 地址。

dmcub_fw_version

DMCUB 固件版本。

cgs_device

通用图形服务设备。它提供了一个用于访问寄存器的接口。

adev

AMDGPU 基本驱动程序结构

ddev

DRM 基本驱动程序结构

display_indexes_num

支持的最大显示流数

atomic_obj

dm_atomic_state 结合使用,它有助于管理全局原子状态,该状态无法完全映射到现有的 DRM 资源中,例如 dc_context

dc_lock

保护对可以发出寄存器写入序列的 DC 函数的访问。

audio_lock

保护对音频实例更改的访问。

audio_component

用于将 ELD 更改通知给声音驱动程序。

audio_registered

如果音频组件已成功注册,则为 True,否则为 False。

irq_handler_list_low_tab

低优先级 IRQ 处理程序表。

它是一个 n*m 表,由 n 个 IRQ 源和每个 IRQ 源 m 个处理程序组成。低优先级 IRQ 处理程序被推迟到工作队列进行处理。因此,它们可以休眠。

请注意,处理程序的调用顺序与它们注册的顺序相同 (FIFO)。

irq_handler_list_high_tab

高优先级 IRQ 处理程序表。

它是一个 n*m 表,与 irq_handler_list_low_tab 相同。但是,此表中的处理程序不会被推迟,而是立即调用。

pflip_params

页面翻转 IRQ 参数,在触发时传递给注册的处理程序。

vblank_params

垂直消隐 IRQ 参数,在触发时传递给注册的处理程序。

vline0_params

OTG 垂直中断 0 IRQ 参数,在触发时传递给注册的处理程序。

vupdate_params

垂直更新 IRQ 参数,在触发时传递给注册的处理程序。

dmub_trace_params

DMUB 跟踪事件 IRQ 参数,在触发时传递给注册的处理程序。

dmub_outbox_params

DMUB 出站箱参数

irq_handler_list_table_lock

同步对 IRQ 表的访问

backlight_dev

背光控制设备

backlight_link

要在其上控制背光的链路

num_of_edps

背光 eDP 的数量

backlight_caps

背光设备的功能

freesync_module

处理 freesync 计算的模块

hdcp_workqueue

AMDGPU 内容保护队列

vblank_control_workqueue

垂直消隐控制事件的延迟工作。

idle_workqueue

空闲事件的定期工作。

cached_state

缓存设备原子状态以进行挂起/恢复

cached_dc_state

内容流的缓存状态

compressor

帧缓冲区压缩缓冲区。请参阅 struct dm_compressor_info

fw_dmcu

对 DMCU 固件的引用

dmcu_fw_version

DMCU 固件的版本

soc_bounding_box

gpu_info FW 提供的 soc 边界框结构,如果 FW 中不可用,则为 0

active_vblank_irq_count

当前活动的垂直消隐 irq 的数量

secure_display_ctx

存储安全显示相关信息。例如,ROI 信息、用于命令 dmub 的 work_struct 等。

hpd_rx_offload_wq

用于卸载 hpd_rx_irq 工作的队列

mst_encoders

用于 DP MST 的伪编码器。

force_timing_sync

通过 debugfs 设置。设置后,指示将强制所有连接的显示器同步。

disable_hpd_irq

为 true 时,禁用驱动程序中的所有 HPD 和 HPD RX 中断处理

dmcub_trace_event_en

启用 dmcub 跟踪事件

da_list

DAL fb 内存分配列表,用于与 SMU 通信。

dmub_aux_transfer_done

用于指示 DMUB 传输何时完成的结构完成

delayed_hpd_wq

用于延迟 DMUB HPD 工作的工作队列

brightness

缓存的背光值。

actual_brightness

上次成功应用的背光值。

aux_hpd_discon_quirk

当 aux 正在进行时,hpd 断开连接的怪癖。发生在某些英特尔平台上

edp0_on_dp1_quirk

将 edp0 放在 DP1 上的平台的怪癖。

dpia_aux_lock

保护对 DPIA AUX 的访问

bb_from_dmub

在 DCN4+ 的早期初始化期间从 dmub 读取的边界框数据

oem_i2c

OEM i2c 总线

fused_io

dmub 融合 io 接口

struct amdgpu_hdmi_vsdb_info

跟踪 VSDB 信息

定义:

struct amdgpu_hdmi_vsdb_info {
    unsigned int amd_vsdb_version;
    bool freesync_supported;
    unsigned int min_refresh_rate_hz;
    unsigned int max_refresh_rate_hz;
    bool replay_mode;
};

成员

amd_vsdb_version

供应商特定数据块版本,应用于确定要发送哪个供应商特定信息帧 (VSIF)。

freesync_supported

FreeSync 支持。

min_refresh_rate_hz

FreeSync 最小刷新率(以 Hz 为单位)。

max_refresh_rate_hz

FreeSync 最大刷新率(以 Hz 为单位)

replay_mode

支持重播

描述

AMDGPU 通过使用 VSDB 部分支持 HDMI 上的 FreeSync,并且此结构对于跟踪有关 FreeSync 的显示器特定信息很有用。

生命周期

DM(以及随之而来的 DC)在 amdgpu 基本驱动程序中注册为 IP 块。启用 CONFIG_DRM_AMD_DC 后,DM 设备 IP 块将添加到基本驱动程序的设备列表中,以便相应地进行初始化和拆除。

执行此操作的函数在 struct amd_ip_funcs 中作为挂钩提供。

int dm_hw_init(struct amdgpu_ip_block *ip_block)

初始化 DC 设备

参数

struct amdgpu_ip_block *ip_block

指向此硬件实例的 amdgpu_ip_block 的指针。

描述

初始化 struct amdgpu_display_manager 设备。这涉及调用每个 DM 组件的初始化程序,然后使用它们填充结构。

虽然该函数暗示硬件初始化,但硬件和软件都在此处初始化。将它们拆分到它们相关的 init 挂钩是一个未来的 TODO 项。

在此处初始化的一些值得注意的事情

  • 显示核心,软件和硬件

  • 我们需要的 DC 模块(freesync 和颜色管理)

  • DRM 软件状态

  • 中断源和处理程序

  • 垂直消隐支持

  • 调试 FS 条目(如果已启用)

int dm_hw_fini(struct amdgpu_ip_block *ip_block)

拆除 DC 设备

参数

struct amdgpu_ip_block *ip_block

指向此硬件实例的 amdgpu_ip_block 的指针。

描述

拆除 struct amdgpu_display_manager 中需要清理的组件。这涉及清理 DRM 设备、DC 和加载的任何模块。还要刷新 IRQ 工作队列并禁用它们。

中断

DM 在基本驱动程序已经提供的基础上提供了另一层 IRQ 管理。这是一个可以清理的东西,也是一个未来的 TODO 项。

基本驱动程序提供 IRQ 源注册与 DRM、处理程序注册到基本驱动程序的 IRQ 表以及处理程序回调 amdgpu_irq_handler(),DRM 通过它在中断时调用。此通用处理程序查找 IRQ 表,并调用相应的 amdgpu_irq_src_funcs.process 挂钩。

DM 在其之上提供的是两个专门用于上半部分和下半部分 IRQ 处理的 IRQ 表,其中下半部分实现工作队列

它们会覆盖基本驱动程序的 IRQ 表,并且效果可以在 DM 为 amdgpu_irq_src_funcs.process 提供的挂钩中看到。它们都设置为 DM 通用处理程序 amdgpu_dm_irq_handler(),它查找 DM 的 IRQ 表。但是,为了使基本驱动程序识别此挂钩,DM 仍然需要使用基本驱动程序注册 IRQ。请参阅 dce110_register_irq_handlers() 和 dcn10_register_irq_handlers()。

为了将 DC 的硬件中断切换公开给基本驱动程序,DM 实现了 amdgpu_irq_src_funcs.set 挂钩。基本驱动程序通过 amdgpu_irq_update() 调用它来启用或禁用中断。

struct amdgpu_dm_irq_handler_data

DM 中断处理程序的数据。

定义:

struct amdgpu_dm_irq_handler_data {
    struct list_head list;
    interrupt_handler handler;
    void *handler_arg;
    struct amdgpu_display_manager *dm;
    enum dc_irq_source irq_source;
    struct work_struct work;
};

成员

list

引用下一个/上一个处理程序的链表条目

handler

处理程序函数

handler_arg

触发时传递给处理程序的参数

dm

此处理程序所属的 DM

irq_source

此处理程序注册的 DC 中断源

work

work struct

void dm_irq_work_func(struct work_struct *work)

在中断处理程序之外处理 IRQ。

参数

struct work_struct *work

work struct

void unregister_all_irq_handlers(struct amdgpu_device *adev)

从 DM IRQ 表中清除处理程序

参数

struct amdgpu_device *adev

包含 DM 设备的基本驱动程序设备

描述

遍历低上下文和高上下文 IRQ 表并取消分配处理程序。

void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev, struct dc_interrupt_params *int_params, void (*ih)(void*), void *handler_args)

在 DM 中注册处理程序。

参数

struct amdgpu_device *adev

包含 DM 设备的基本驱动程序设备。

struct dc_interrupt_params *int_params

包含源和处理程序上下文的中断参数

void (*ih)(void *)

指向要注册的中断处理程序的函数指针

void *handler_args

中断发生时传递给处理程序的参数

描述

为给定上下文中给定的 IRQ 源注册中断处理程序。上下文可以是高上下文也可以是低上下文。高上下文处理程序直接在 ISR 上下文中执行,而低上下文在工作队列中执行,从而允许休眠操作。

已注册的处理程序以 FIFO 方式调用,即首先调用最近注册的处理程序。

返回

处理程序数据 struct amdgpu_dm_irq_handler_data,其中包含 IRQ

源、处理程序函数和参数

void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev, enum dc_irq_source irq_source, void *ih)

从 DM IRQ 表中删除处理程序

参数

struct amdgpu_device *adev

包含 DM 设备的基本驱动程序设备

enum dc_irq_source irq_source

从中删除给定处理程序的 IRQ 源

void *ih

指向要取消注册的中断处理程序的函数指针

描述

遍历低上下文和高上下文 IRQ 表,并找到给定 irq 源的给定处理程序。如果找到,则删除它。否则,什么也不做。

int amdgpu_dm_irq_init(struct amdgpu_device *adev)

初始化 DM IRQ 管理

参数

struct amdgpu_device *adev

包含 DM 设备的基本驱动程序设备

描述

初始化 DM 的高上下文和低上下文 IRQ 表。

N by M 表包含 N 个 IRQ 源,其中 M 个 struct amdgpu_dm_irq_handler_data 在链表中连接在一起。list_heads 在此处初始化。当中断 n 被触发时,所有 m 个处理程序按注册顺序依次调用 (FIFO)。

低上下文表需要特殊的初始化步骤,因为处理程序将被推迟到工作队列。请参阅 struct irq_list_head

void amdgpu_dm_irq_fini(struct amdgpu_device *adev)

拆除 DM IRQ 管理

参数

struct amdgpu_device *adev

包含 DM 设备的基本驱动程序设备

描述

刷新低上下文 IRQ 表中的所有工作。

int amdgpu_dm_irq_handler(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry)

通用 DM IRQ 处理程序

参数

struct amdgpu_device *adev

amdgpu 基本驱动程序设备,其中包含 DM 设备

struct amdgpu_irq_src *source

未使用

struct amdgpu_iv_entry *entry

有关触发的中断的数据

描述

立即调用所有已注册的高 irq 工作,并计划低 irq 的工作。DM IRQ 表用于查找相应的处理程序。

void amdgpu_dm_hpd_init(struct amdgpu_device *adev)

hpd 设置回调。

参数

struct amdgpu_device *adev

amdgpu_device 指针

描述

设置卡使用的 hpd 引脚(evergreen+)。启用引脚,设置极性,然后启用 hpd 中断。

void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)

hpd 拆卸回调。

参数

struct amdgpu_device *adev

amdgpu_device 指针

描述

拆卸卡使用的 hpd 引脚(evergreen+)。禁用 hpd 中断。

void dm_pflip_high_irq(void *interrupt_params)

处理页面翻转中断

参数

void *interrupt_params

已忽略

描述

通过通知所有相关方页面翻转已完成来处理页面翻转中断。

void dm_crtc_high_irq(void *interrupt_params)

处理 CRTC 中断

参数

void *interrupt_params

用于确定 CRTC 实例

描述

通过通知 DRM 的 VBLANK 事件处理程序来处理 CRTC/VSYNC 中断。

原子实现

正在进行中

void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)

AMDgpu DM 的提交尾部实现。

参数

struct drm_atomic_state *state

要提交的原子状态

描述

这将告诉 DC 从 atomic_check 提交构造的 DC 状态,从而对硬件进行编程。这里的任何故障都意味着硬件故障,因为原子检查应该已经过滤掉了任何非 kos。

int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)

AMDgpu DM 的原子检查实现。

参数

struct drm_device *dev

DRM 设备

struct drm_atomic_state *state

要提交的原子状态

描述

验证给定的原子状态是否可以通过 DC 编程到硬件中。这包括构造一个 struct dc_state,反映我们希望提交的新的硬件状态,然后查询 DC 以查看它是否可编程。重要的是不要修改现有的 DC 状态。否则,atomic_check 可能会意外地提交硬件更改。

验证 DC 状态时,获取正确的锁非常重要。对于完全更新的情况,即在一个 CRTC 上删除/添加/更新流,同时在另一个 CRTC 上翻转,获取全局锁将保证任何此类完全更新提交都会等待使用 DRM 同步事件完成任何未完成的翻转。

请注意,DM 会为状态中的所有 CRTC 添加受影响的连接器,即使这似乎没有必要。这是因为 DC 流创建需要 DC sink,而 DC sink 与 DRM 连接器状态相关联。清理这一点应该是可能的,但并非易事 - 一个可能的 TODO 项。

返回

- 如果验证失败,则返回错误代码。

颜色管理属性

HW 的 DC 接口为我们提供了每个管道(表面)的以下颜色管理块

  • 输入 gamma LUT(反归一化)

  • 输入 CSC(归一化)

  • 表面 degamma LUT(归一化)

  • 表面 CSC(归一化)

  • 表面 regamma LUT(归一化)

  • 输出 CSC(归一化)

但这些并不是 DRM 颜色属性的直接映射。当前的 DRM 接口公开了 CRTC degamma、CRTC CTM 和 CRTC regamma,而我们的硬件本质上是提供

Plane CTM -> Plane degamma -> Plane CTM -> Plane regamma -> Plane CTM

输入 gamma LUT 块并不真正适用于此,因为它作用于实际的输入数据本身,而不是 HW fp 表示。输入和输出 CSC 块在技术上可以用作 DC 接口的一部分,但通常由 DC 在内部用于颜色空间之间的转换。这些将来可以与用户调整混合在一起,但目前应该保持不变。

管道混合也发生在这些块之后,因此我们实际上不支持任何具有与多个平面正确混合的 CRTC 属性 - 但在大多数单平面情况下,通过巧妙地管理 DM 中的 DC 接口,我们仍然可以正确地支持 DM 中的 CRTC 颜色管理属性。

根据 DRM 文档,当各自的属性设置为 NULL 时,块应处于硬件旁路状态。线性 DGM/RGM LUT 也应被视为将各自的块置于旁路模式。

这意味着以下配置被假定为默认配置

Plane DGM Bypass -> Plane CTM Bypass -> Plane RGM Bypass -> ... CRTC DGM Bypass -> CRTC CTM Bypass -> CRTC RGM Bypass

void amdgpu_dm_init_color_mod(void)

初始化颜色模块。

参数

void

无参数

描述

我们没有使用完整的颜色模块,只使用某些组件。只为我们需要的组件调用设置函数。

const struct drm_color_lut *__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)

从 blob 中提取 DRM lut 和 lut 大小。

参数

const struct drm_property_blob *blob

DRM 颜色管理属性 blob

uint32_t *size

lut 大小

返回

DRM LUT 或 NULL

bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)

检查给定的 lut 是否是值的线性映射

参数

const struct drm_color_lut *lut

给定的 lut 以检查值

uint32_t size

lut 大小

描述

如果 lut 表示:f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a;对于 [0, MAX_COLOR_LUT_ENTRIES) 中的整数 a,则认为它是线性的

返回

如果给定的 lut 是值的线性映射,即它充当旁路 LUT,则为 True。否则为 false。

void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut, struct dc_gamma *gamma, bool is_legacy)

将 drm_color_lut 转换为 dc_gamma。

参数

const struct drm_color_lut *lut

用于颜色转换的 DRM 查找表

struct dc_gamma *gamma

DC gamma 设置条目

bool is_legacy

旧式或原子 gamma

描述

转换取决于 lut 的大小 - 是否为旧式。

void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, struct fixed31_32 *matrix)

将 DRM CTM 转换为 DC CSC 浮点矩阵

参数

const struct drm_color_ctm *ctm

DRM 颜色转换矩阵

struct fixed31_32 *matrix

DC CSC 浮点矩阵

描述

矩阵需要是 3x4(12 个条目)矩阵。

void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm, struct fixed31_32 *matrix)

将 DRM CTM 3x4 转换为 DC CSC 浮点矩阵

参数

const struct drm_color_ctm_3x4 *ctm

具有 3x4 维度的 DRM 颜色转换矩阵

struct fixed31_32 *matrix

DC CSC 浮点矩阵

描述

矩阵需要是 3x4(12 个条目)矩阵。

int __set_legacy_tf(struct dc_transfer_func *func, const struct drm_color_lut *lut, uint32_t lut_size, bool has_rom)

计算旧式传输函数

参数

struct dc_transfer_func *func

传输函数

const struct drm_color_lut *lut

定义颜色空间的查找表

uint32_t lut_size

各自 lut 的大小

bool has_rom

如果 ROM 可以用于硬编码曲线

描述

仅适用于 sRGB 输入空间

返回

成功时为 0,失败时为 -ENOMEM

int __set_output_tf(struct dc_transfer_func *func, const struct drm_color_lut *lut, uint32_t lut_size, bool has_rom)

根据预期的输入空间计算输出传输函数。

参数

struct dc_transfer_func *func

传输函数

const struct drm_color_lut *lut

定义颜色空间的查找表

uint32_t lut_size

各自 lut 的大小

bool has_rom

如果 ROM 可以用于硬编码曲线

返回

成功时为 0。如果失败,则为 -ENOMEM。

int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func, const struct drm_color_lut *lut, uint32_t lut_size)

根据预期的输入空间计算输入传输函数。

参数

struct dc_color_caps *caps

dc 颜色功能

struct dc_transfer_func *func

传输函数

const struct drm_color_lut *lut

定义颜色空间的查找表

uint32_t lut_size

各自 lut 的大小。

返回

成功时为 0。如果失败,则为 -ENOMEM。

int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, struct drm_plane_state *plane_state)

验证是否支持 3D LUT,以及用户整形器和 3D LUT 是否与硬件支持的大小匹配

参数

struct amdgpu_device *adev

amdgpu 设备

struct drm_plane_state *plane_state

DRM 平面状态

描述

验证 HW(DCN 2.0 或更高版本)是否支持预混合 (DPP) 3D LUT,以及用户整形器和 3D LUT 是否与支持的大小匹配。

返回

成功时为 0。如果 lut 大小无效,则为 -EINVAL。

int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)

验证 DRM lut 是否与硬件支持的大小匹配

参数

const struct drm_crtc_state *crtc_state

DRM CRTC 状态

描述

验证附加到 crtc_state 的 Degamma 和 Gamma LUT 是否为预期的大小。

返回

成功时为 0。如果任何 lut 大小无效,则为 -EINVAL。

int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)

将 DRM 颜色管理映射到 DC 流。

参数

struct dm_crtc_state *crtc

amdgpu_dm crtc 状态

描述

在没有平面级别颜色管理属性的情况下,我们可以自由使用任何 HW 块,只要 CRTC CTM 始终位于 CRTC RGM 之前和 CRTC DGM 之后即可。

  • 如果 CRTC RGM 块是非线性的,则将其放置在 RGM LUT 块中。

  • 如果 CRTC DGM 块是非线性的,则将其放置在 DGM LUT 块中。

  • 如果 CRTC CTM 是非线性的,则将其放置在色域重映射块中。

RGM 块通常在所有 ASIC 中都具有更完整的功能和更高的准确性 - DCE 不能支持自定义非线性 CRTC DGM。

为了同时支持平面级别颜色管理和 CRTC 级别颜色管理,我们必须限制 CRTC 属性的使用或将调整混合在一起。

返回

成功时为 0。如果设置失败,则返回错误代码。

int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state)

将 DRM 颜色管理映射到 DC 平面。

参数

struct dm_crtc_state *crtc

amdgpu_dm crtc 状态

struct drm_plane_state *plane_state

DRM 平面状态

struct dc_plane_state *dc_plane_state

目标 DC 表面

描述

更新底层 dc_stream_state 的输入传输函数 (ITF),以准备进行硬件提交。使用的传输函数取决于为颜色管理在流上完成的准备工作。

返回

成功时为 0。如果内存分配失败,则返回 -ENOMEM。

DCN 代之间的 DC 颜色功能

DRM/KMS 框架定义了三个 CRTC 颜色校正属性:degamma、颜色变换矩阵 (CTM) 和 gamma,以及两个 degamma 和 gamma LUT 大小的属性。AMD DC 编程一些预混合的颜色校正功能,但 DRM/KMS 没有每个平面的颜色校正属性。

一般来说,DRM CRTC 颜色属性被编程到 DC,如下所示:混合后的 CRTC gamma 和预混合的 CRTC degamma。虽然 CTM 在混合后被编程,但它被映射到 DPP 硬件块(预混合)。硬件中提供的其他颜色 caps 当前未由 DRM 接口公开,并且被绕过。

颜色管理 caps(DPP 和 MPC)

Modules/color 计算各种颜色操作,这些操作被转换为抽象的 HW。DCE 5-12 几乎没有重要的更改,但从 DCN1 开始,每一代新产品在颜色管道方面都有相当大的差异。因此,我们抽象颜色管道功能,以便模块/DM 可以根据逻辑功能决定映射到 HW 块。

MAX_SURFACES

MAX_SURFACES

表示可以管道传输到单个 CRTC 的表面的上限

MAX_PLANES

MAX_PLANES

表示 HW 支持的平面的上限

struct rom_curve_caps

degamma 和 regamma 的预定义传输函数 caps

定义:

struct rom_curve_caps {
    uint16_t srgb : 1;
    uint16_t bt2020 : 1;
    uint16_t gamma2_2 : 1;
    uint16_t pq : 1;
    uint16_t hlg : 1;
};

成员

srgb

RGB 颜色空间传输函数

bt2020

BT.2020 传输函数

gamma2_2

标准 gamma

pq

感知量化器传输函数

hlg

混合对数 gamma 传输函数

struct dpp_color_caps

显示管道和平面块的颜色管道功能

定义:

struct dpp_color_caps {
    uint16_t dcn_arch : 1;
    uint16_t input_lut_shared : 1;
    uint16_t icsc : 1;
    uint16_t dgam_ram : 1;
    uint16_t post_csc : 1;
    uint16_t gamma_corr : 1;
    uint16_t hw_3d_lut : 1;
    uint16_t ogam_ram : 1;
    uint16_t ocsc : 1;
    uint16_t dgam_rom_for_yuv : 1;
    struct rom_curve_caps dgam_rom_caps;
    struct rom_curve_caps ogam_rom_caps;
};

成员

dcn_arch

所有 DCE 代都以相同的方式处理

input_lut_shared

与 DGAM 共享。输入 LUT 与大多数 LUT 不同,只是普通的 256 条目查找

icsc

输入颜色空间转换

dgam_ram

可编程 degamma LUT

post_csc

色域重映射之前的后颜色空间转换

gamma_corr

degamma 校正

hw_3d_lut

3D LUT 支持。它意味着之前的整形器 LUT。可以通过设置 mpc:shared_3d_lut 标志与 MPC 共享

ogam_ram

可编程输出/混合 gamma LUT

ocsc

输出颜色空间转换

dgam_rom_for_yuv

YUV 平面的预定义 degamma LUT

dgam_rom_caps

degamma 1D LUT 的预定义曲线 caps

ogam_rom_caps

regamma 1D LUT 的预定义曲线 caps

注意

hdr_mult 和色域重映射 (CTM) 始终在 DPP 中可用(按此顺序)

struct mpc_color_caps

多个管道和平面组合块的颜色管道功能

定义:

struct mpc_color_caps {
    uint16_t gamut_remap : 1;
    uint16_t ogam_ram : 1;
    uint16_t ocsc : 1;
    uint16_t num_3dluts : 3;
    uint16_t shared_3d_lut:1;
    struct rom_curve_caps ogam_rom_caps;
};

成员

gamut_remap

颜色转换矩阵

ogam_ram

可编程输出 gamma LUT

ocsc

输出颜色空间转换矩阵

num_3dluts

MPC 3D LUT;始终假定前面的整形器 LUT

shared_3d_lut

共享 3D LUT 标志。可以是 DPP 或 MPC,但单实例

ogam_rom_caps

regamma 1D LUT 的预定义曲线 caps

struct dc_color_caps

DPP 和 MPC 硬件块的颜色管道功能

定义:

struct dc_color_caps {
    struct dpp_color_caps dpp;
    struct mpc_color_caps mpc;
};

成员

dpp

DPP 的颜色管道 caps

mpc

MPC 的颜色管道 caps

enum pipe_split_policy

DCN 支持的管道拆分策略

常量

MPC_SPLIT_DYNAMIC

DC 将自动决定如何拆分管道,以便在性能和功耗之间实现最佳折衷。这是推荐的选项。

MPC_SPLIT_AVOID

避免管道拆分,这意味着 DC 不会尝试任何类型的拆分优化。

MPC_SPLIT_AVOID_MULT_DISP

使用此选项,DC 仅在使用单个显示器时尝试优化管道利用率;如果用户连接到第二个显示器,DC 将避免管道拆分。

描述

此枚举用于定义 DCN 支持的管道拆分策略。默认情况下,DC 倾向于 MPC_SPLIT_DYNAMIC。

struct dc_validation_set

用于存储表面/流关联以进行验证的结构

定义:

struct dc_validation_set {
    struct dc_stream_state *stream;
    struct dc_plane_state *plane_states[MAX_SURFACES];
    uint8_t plane_count;
};

成员

stream

流状态属性

plane_states

表面状态

plane_count

活动平面的总数

颜色管道在 DCN 硬件代之间经历了重大变化。在混合之前和之后可以做什么取决于硬件功能,如下面的 DCN 2.0 和 DCN 3.0 系列架构所示。

DCN 2.0 系列颜色 caps 和映射

../../../_images/dcn2_cm_drm_current.svg

DCN 3.0 系列颜色 caps 和映射

../../../_images/dcn3_cm_drm_current.svg

混合模式属性

像素混合模式是 drm_plane 的 DRM 平面合成属性,用于描述如何将前景平面 (fg) 的像素与背景平面 (bg) 合成。在这里,我们介绍 DRM 混合模式的主要概念,以帮助了解此属性如何映射到 AMD DC 接口。有关此 DRM 属性和 alpha 混合方程的更多信息,请参见DRM 平面合成属性

基本上,混合模式设置平面合成的 alpha 混合方程,该方程适合 alpha 通道影响像素颜色值的状态,因此,影响生成的像素颜色的模式。例如,考虑 alpha 混合方程的以下元素

  • fg.rgb:前景像素的每个 RGB 分量值。

  • fg.alpha:前景像素的 Alpha 分量值。

  • bg.rgb:背景的每个 RGB 分量值。

  • plane_alpha:由平面“alpha”属性设置的平面 alpha 值,有关更多信息,请参见DRM 平面合成属性

在基本 alpha 混合方程中

out.rgb = alpha * fg.rgb + (1 - alpha) * bg.rgb

忽略平面中每个像素的 alpha 通道值,只有平面 alpha 影响生成的像素颜色值。

DRM 有三种混合模式来定义平面合成中的混合公式

  • None:忽略像素 alpha 的混合公式。

  • Pre-multiplied:假设平面中的像素颜色值在存储之前已经乘以其自身的 alpha 通道的混合公式。

  • Coverage:假设像素颜色值未与 alpha 通道值预乘的混合公式。

预乘是默认像素混合模式,这意味着,当未创建或定义混合模式属性时,DRM 认为平面的像素具有预乘的颜色值。在 IGT GPU 工具上,kms_plane_alpha_blend 测试提供了一组子测试来验证平面 alpha 和混合模式属性。

然后,DRM 混合模式及其元素由 AMDGPU 显示管理器 (DM) 映射,以编程多个管道/平面组合 (MPC) 的混合配置,如下所示

因此,MPC 树上单个 MPCC 实例的混合配置由 mpcc_blnd_cfg 定义,其中 pre_multiplied_alpha 是用于设置 MPCC_ALPHA_MULTIPLIED_MODE 的 alpha 预乘模式标志。它控制是否乘以 alpha(true/false),仅对于 DRM 预乘混合模式为 true。mpcc_alpha_blend_mode 定义关于像素 alpha 和平面 alpha 值的 alpha 混合模式。它为 MPCC_ALPHA_BLND_MODE 设置三种模式之一,如下所述。

然后,DM 将 enum mpcc_alpha_blend_mode 的元素映射到 DRM 混合公式中的元素,如下所示

  • MPC 像素 alpha 匹配 DRM fg.alpha 作为平面像素的 alpha 分量值

  • 当应忽略像素 alpha 且像素值未预乘时,MPC 全局 alpha 匹配 DRM plane_alpha

  • DRM fg.alphaDRM plane_alpha 都参与混合方程时,MPC 全局增益 假定 MPC 全局 alpha

简而言之,通过选择 MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA 忽略 fg.alpha。另一方面,通过选择 MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN,(plane_alpha * fg.alpha) 分量变为可用。并且 MPCC_ALPHA_MULTIPLIED_MODE 定义像素颜色值是否乘以 alpha。

混合配置流程

alpha 混合方程通过以下路径从 DRM 配置到 DC 接口

  1. 更新 drm_plane_state 时,DM 调用 amdgpu_dm_plane_fill_blending_from_plane_state(),将 drm_plane_state 属性映射到 dc_plane_info 结构,以便在与操作系统无关的组件 (DC) 中处理。

  2. 在 DC 接口上,struct mpcc_blnd_cfg 考虑来自 DPP 的 dc_plane_info 输入,来编程 MPCC 混合配置。