drm/tegra NVIDIA Tegra GPU 和显示驱动程序¶
NVIDIA Tegra SoC 通过 host1x 控制器支持一组显示、图形和视频功能。 host1x 通过通道将其客户端直接提供的推送缓冲区收集的命令流提供给客户端。 软件或块本身可以使用同步点进行同步。
直到但不包括 Tegra124(又名 Tegra K1),drm/tegra 驱动程序都支持内置 GPU,它由 gr2d 和 gr3d 引擎组成。 从 Tegra124 开始,GPU 基于 NVIDIA 桌面 GPU 架构,并由 drm/nouveau 驱动程序支持。
drm/tegra 驱动程序支持自 Tegra20 以来的 NVIDIA Tegra SoC 世代。 它有三个部分
host1x 驱动程序,提供基础架构和对 host1x 服务的访问。
KMS 驱动程序,支持显示控制器以及许多输出,例如 RGB、HDMI、DSI 和 DisplayPort。
一组自定义用户空间 IOCTL,可用于通过 host1x 将作业提交到 GPU 和视频引擎。
驱动程序基础架构¶
各种 host1x 客户端需要绑定在一起到一个逻辑设备中,以便向用户公开其功能。 支持此功能的基础架构在 host1x 驱动程序中实现。 当驱动程序在基础架构中注册时,它会提供一个兼容字符串列表,指定它需要的设备。 基础架构创建一个逻辑设备,并扫描设备树以查找匹配的设备节点,将所需的客户端添加到列表中。 各个客户端的驱动程序也向基础架构注册,并添加到逻辑 host1x 设备中。
一旦所有客户端都可用,基础架构将使用驱动程序提供的函数初始化逻辑设备,该函数将设置子系统特定的位,并依次初始化其每个客户端。
类似地,当其中一个客户端取消注册时,基础架构将通过回调到驱动程序来销毁逻辑设备,这确保了子系统特定的位被拆除,并且客户端依次被销毁。
Host1x 基础架构参考¶
-
struct host1x_bo_cache¶
host1x 缓冲区对象缓存
定义:
struct host1x_bo_cache {
struct list_head mappings;
struct mutex lock;
};
成员
映射
映射列表
锁定
同步对映射列表的访问
描述
请注意,条目不会定期从该缓存中清除,而是需要显式释放。 这主要用于 DRM/KMS,其中当表示此缓存中映射的缓冲区对象的最后一个引用被删除时,缓存的引用将被释放。
-
struct host1x_client_ops¶
host1x 客户端操作
定义:
struct host1x_client_ops {
int (*early_init)(struct host1x_client *client);
int (*init)(struct host1x_client *client);
int (*exit)(struct host1x_client *client);
int (*late_exit)(struct host1x_client *client);
int (*suspend)(struct host1x_client *client);
int (*resume)(struct host1x_client *client);
};
成员
early_init
host1x 客户端提前初始化代码
init
host1x 客户端初始化代码
exit
host1x 客户端拆卸代码
late_exit
host1x 客户端后期拆卸代码
suspend
host1x 客户端挂起代码
resume
host1x 客户端恢复代码
-
struct host1x_client¶
host1x 客户端结构
定义:
struct host1x_client {
struct list_head list;
struct device *host;
struct device *dev;
struct iommu_group *group;
const struct host1x_client_ops *ops;
enum host1x_class class;
struct host1x_channel *channel;
struct host1x_syncpt **syncpts;
unsigned int num_syncpts;
struct host1x_client *parent;
unsigned int usecount;
struct mutex lock;
struct host1x_bo_cache cache;
};
成员
list
host1x 客户端的列表节点
host
指向表示 host1x 控制器的
struct device
的指针dev
指向支持此 host1x 客户端的
struct device
的指针group
此客户端所属的 IOMMU 组
ops
host1x 客户端操作
class
此客户端表示的 host1x 类
channel
与此客户端关联的 host1x 通道
syncpts
为此客户端请求的同步点数组
num_syncpts
为此客户端请求的同步点数量
parent
指向父结构的指针
usecount
此结构的引用计数
锁定
互斥锁
cache
host1x 缓冲区对象缓存
-
struct host1x_driver¶
host1x 逻辑设备驱动程序
定义:
struct host1x_driver {
struct device_driver driver;
const struct of_device_id *subdevs;
struct list_head list;
int (*probe)(struct host1x_device *device);
int (*remove)(struct host1x_device *device);
void (*shutdown)(struct host1x_device *device);
};
成员
driver
核心驱动程序
subdevs
匹配此驱动程序的子设备的 OF 设备 ID 表
list
list node for the driver
probe
在探测 host1x 逻辑设备时调用
remove
在删除 host1x 逻辑设备时调用
shutdown
在关闭 host1x 逻辑设备时调用
-
int host1x_device_init(struct host1x_device *device)¶
初始化 host1x 逻辑设备
参数
struct host1x_device *device
host1x 逻辑设备
描述
host1x 逻辑设备的驱动程序可以在其 host1x_driver.probe
实现的执行期间调用此函数来初始化其每个客户端。 客户端驱动程序使用 host1x_client.parent
字段和与其关联的驱动程序数据(通常通过调用 dev_get_drvdata())来访问子系统特定的驱动程序数据。
-
int host1x_device_exit(struct host1x_device *device)¶
取消初始化 host1x 逻辑设备
参数
struct host1x_device *device
host1x 逻辑设备
描述
当 host1x 逻辑设备的驱动程序被卸载时,它可以调用此函数来拆卸其每个客户端。 通常,这是在删除子系统特定的数据结构并且该功能不再可以使用之后完成的。
-
int host1x_driver_register_full(struct host1x_driver *driver, struct module *owner)¶
注册 host1x 驱动程序
参数
struct host1x_driver *driver
host1x 驱动程序
struct module *owner
所有者模块
描述
host1x 逻辑设备的驱动程序调用此函数以在基础架构中注册驱动程序。 请注意,由于这些驱动器逻辑设备,因此驱动程序的注册实际上会触发逻辑设备的创建。 将为每个 host1x 实例创建一个逻辑设备。
-
void host1x_driver_unregister(struct host1x_driver *driver)¶
注销 host1x 驱动程序
参数
struct host1x_driver *driver
host1x 驱动程序
描述
从其绑定的每个 host1x 逻辑设备中取消绑定驱动程序,有效地删除了它们表示的子系统设备。
-
void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key)¶
初始化 host1x 客户端
参数
struct host1x_client *client
host1x 客户端
struct lock_class_key *key
客户端特定互斥锁的锁定类密钥
-
void host1x_client_exit(struct host1x_client *client)¶
取消初始化 host1x 客户端
参数
struct host1x_client *client
host1x 客户端
-
int __host1x_client_register(struct host1x_client *client)¶
注册 host1x 客户端
参数
struct host1x_client *client
host1x 客户端
描述
将 host1x 客户端注册到每个 host1x 控制器实例。 请注意,每个客户端将仅匹配其父 host1x 控制器,并且将仅与该实例关联。 一旦所有客户端都已向其父 host1x 控制器注册,基础架构将设置逻辑设备并调用 host1x_device_init()
,这反过来将调用每个客户端的 host1x_client_ops.init
实现。
-
void host1x_client_unregister(struct host1x_client *client)¶
注销 host1x 客户端
参数
struct host1x_client *client
host1x 客户端
描述
从其 host1x 控制器实例中删除 host1x 客户端。 如果已初始化逻辑设备,则会将其拆卸。
Host1x 同步点参考¶
-
struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, unsigned long flags, const char *name)¶
分配同步点
参数
struct host1x *host
host1x 设备数据
unsigned long flags
HOST1X_SYNCPT_* 标志的位域
const char *name
同步点的名称,用于调试打印
描述
为调用者分配硬件同步点以供使用。 然后,调用者拥有唯一权限来更改同步点的值,直到再次释放它。
如果没有可用的空闲同步点,或者指定了 NULL 名称,则返回 NULL。
-
u32 host1x_syncpt_id(struct host1x_syncpt *sp)¶
检索同步点 ID
参数
struct host1x_syncpt *sp
host1x 同步点
描述
给定指向 struct host1x_syncpt 的指针,检索其 ID。 此 ID 通常用作一个值,用于编程到控制硬件块如何与同步点交互的寄存器中。
-
u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)¶
更新发送到硬件的值
参数
struct host1x_syncpt *sp
host1x 同步点
u32 incrs
增量数
-
int host1x_syncpt_incr(struct host1x_syncpt *sp)¶
从 CPU 递增同步点值,更新缓存
参数
struct host1x_syncpt *sp
host1x 同步点
-
int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, u32 *value)¶
等待同步点达到给定的值
参数
struct host1x_syncpt *sp
host1x 同步点
u32 thresh
阈值
long timeout
等待同步点达到给定值的最大时间
u32 *value
同步点值的返回位置
-
struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client, unsigned long flags)¶
请求同步点
参数
struct host1x_client *client
请求同步点的客户端
unsigned long flags
flags
描述
host1x 客户端驱动程序可以使用此函数来分配同步点以供后续使用。 此函数返回的同步点将专门保留供客户端使用。 当不再使用同步点时,host1x 客户端驱动程序需要使用 host1x_syncpt_put()
释放它。
-
void host1x_syncpt_put(struct host1x_syncpt *sp)¶
释放请求的同步点
参数
struct host1x_syncpt *sp
host1x 同步点
描述
释放先前使用 host1x_syncpt_request()
分配的同步点。 当不再使用同步点时,host1x 客户端驱动程序应调用此函数。
-
u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)¶
读取最大同步点值
参数
struct host1x_syncpt *sp
host1x 同步点
描述
最大同步点值指示队列中有多少操作,无论是在通道中还是在软件线程中。
-
u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)¶
读取最小同步点值
参数
struct host1x_syncpt *sp
host1x 同步点
描述
最小同步点值是硬件中当前同步点值的阴影。
-
u32 host1x_syncpt_read(struct host1x_syncpt *sp)¶
读取当前同步点值
参数
struct host1x_syncpt *sp
host1x 同步点
-
struct host1x_syncpt *host1x_syncpt_get_by_id(struct host1x *host, unsigned int id)¶
通过 ID 获取同步点
参数
struct host1x *host
host1x 控制器
unsigned int id
同步点 ID
-
struct host1x_syncpt *host1x_syncpt_get_by_id_noref(struct host1x *host, unsigned int id)¶
通过 ID 获取同步点,但不增加引用计数。
参数
struct host1x *host
host1x 控制器
unsigned int id
同步点 ID
-
struct host1x_syncpt *host1x_syncpt_get(struct host1x_syncpt *sp)¶
递增同步点引用计数
参数
struct host1x_syncpt *sp
同步点
-
struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)¶
获取与同步点关联的等待基址
参数
struct host1x_syncpt *sp
host1x 同步点
-
u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)¶
检索同步点等待基址的 ID
参数
struct host1x_syncpt_base *base
host1x 同步点等待基址
-
void host1x_syncpt_release_vblank_reservation(struct host1x_client *client, u32 syncpt_id)¶
使 VBLANK 同步点可用于分配
参数
struct host1x_client *client
host1x 总线客户端
u32 syncpt_id
要提供的同步点 ID
描述
如果 VBLANK<i> 同步点在初始化时被保留,则使其可用于分配。 这应该由显示驱动程序在确保已禁用由引导链配置的任何 VBLANK 递增编程后调用。
KMS 驱动程序¶
在各种 Tegra SoC 世代中,显示硬件基本上保持了向后兼容性,直到 Tegra186,它引入了一些变化,使得很难使用参数化驱动程序来支持它。
显示控制器¶
Tegra SoC 有两个显示控制器,每个控制器可以与零个或多个输出相关联。 输出也可以共享单个显示控制器,但前提是它们以兼容的显示时序运行。 两个显示控制器也可以共享单个帧缓冲区,即使两个输出上的模式不匹配,也允许克隆配置。 在 KMS 术语中,显示控制器被建模为 CRTC。
在 Tegra186 上,显示控制器的数量已增加到三个。 显示控制器不能再驱动所有输出。 虽然其中两个控制器可以驱动两个 DSI 输出和两个 SOR 输出,但第三个控制器无法驱动任何 DSI。
窗口¶
显示控制器控制一组窗口,这些窗口可用于将多个缓冲区合成到屏幕上。 虽然可以将任意 Z 排序分配给各个窗口(通过编程相应的混合寄存器),但驱动程序当前不支持此功能。 相反,它将假定窗口的固定 Z 排序(窗口 A 是根窗口,即最低的,而窗口 B 和 C 叠加在窗口 A 的顶部)。 覆盖窗口支持多种像素格式,并且可以在扫描输出时自动从 YUV 转换为 RGB。 这使得它们对于显示视频内容非常有用。 在 KMS 中,每个窗口都建模为一个平面。 每个显示控制器都有一个硬件光标,该光标作为光标平面公开。
输出¶
支持的输出类型和数量因 Tegra SoC 世代而异。 所有世代都至少支持 HDMI。 虽然早期的世代支持非常简单的 RGB 接口(每个显示控制器一个),但最近的世代不再支持,而是提供标准接口,例如 DSI 和 eDP/DP。
输出建模为复合编码器/连接器对。
RGB/LVDS¶
自 Tegra124 以来,此接口不再可用。 它已被更标准的 DSI 和 eDP 接口取代。
HDMI¶
所有 Tegra SoC 都支持 HDMI。 从 Tegra210 开始,HDMI 由多功能的 SOR 输出提供,该输出支持 eDP、DP 和 HDMI。 SOR 能够支持 HDMI 2.0,但目前尚未合并对此的支持。
DSI¶
虽然 Tegra 自 Tegra30 以来就支持 DSI,但控制器在 Tegra114 中以多种方式发生了变化。 由于在 Dalmore (Tegra114) 之前的任何公开提供的开发板都没有使用 DSI,因此只有 drm/tegra 驱动程序支持 Tegra114 和更高版本。
eDP/DP¶
eDP 首先在 Tegra124 中引入,用于驱动笔记本电脑外形尺寸的显示面板。 Tegra210 增加了对完整 DisplayPort 支持的支持,尽管这目前尚未在 drm/tegra 驱动程序中实现。
用户空间接口¶
drm/tegra 提供的用户空间接口允许应用程序创建 GEM 缓冲区、访问和控制同步点以及将命令流提交到 host1x。
GEM 缓冲区¶
DRM_IOCTL_TEGRA_GEM_CREATE
IOCTL 用于使用 Tegra 特定的标志创建 GEM 缓冲区对象。 这对于应该平铺的缓冲区或要倒置扫描的缓冲区(对于 3D 内容很有用)很有用。
创建 GEM 缓冲区对象后,可以使用 DRM_IOCTL_TEGRA_GEM_MMAP
IOCTL 返回的 mmap 偏移量由应用程序映射其内存。
同步点¶
可以通过执行 DRM_IOCTL_TEGRA_SYNCPT_READ
IOCTL 来获取同步点的当前值。 递增同步点是使用 DRM_IOCTL_TEGRA_SYNCPT_INCR
IOCTL 实现的。
用户空间还可以请求阻塞同步点。 为此,它需要执行 DRM_IOCTL_TEGRA_SYNCPT_WAIT
IOCTL,指定要等待的同步点的值。 当同步点达到该值或在指定的超时时间后,内核将释放应用程序。
命令流提交¶
在应用程序可以将命令流提交到 host1x 之前,它需要使用 DRM_IOCTL_TEGRA_OPEN_CHANNEL
IOCTL 打开到引擎的通道。 客户端 ID 用于标识通道的目标。 当不再需要通道时,可以使用 DRM_IOCTL_TEGRA_CLOSE_CHANNEL
IOCTL 关闭通道。 要检索与通道关联的同步点,应用程序可以使用 DRM_IOCTL_TEGRA_GET_SYNCPT
。
打开通道后,提交命令流很容易。 应用程序将命令写入备份 GEM 缓冲区对象的内存中,并将这些命令传递给 DRM_IOCTL_TEGRA_SUBMIT
IOCTL 以及各种其他参数,例如作业提交中使用的同步点或重定位。