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 以及各種其他引數,例如作業提交中使用的同步點或重定位。