drm/tegra NVIDIA Tegra GPU 和显示驱动程序¶
NVIDIA Tegra SoC 通过 host1x 控制器支持一组显示、图形和视频功能。host1x 通过通道将其从 CPU 直接提供的推送缓冲区收集的命令流提供给其客户端。软件或块之间可以使用同步点进行同步。
直到但不包括 Tegra124(又名 Tegra K1),drm/tegra 驱动程序都支持内置 GPU,该 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;
};
成员
mappings
映射列表
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 客户端操作
类
此客户端表示的 host1x 类
channel
与此客户端关联的 host1x 通道
syncpts
为此客户端请求的同步点数组
num_syncpts
为此客户端请求的同步点数
parent
指向父结构的指针
usecount
此结构的引用计数
lock
用于互斥并发的互斥锁
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
驱动程序的列表节点
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
标志
描述
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。