drm/komeda Arm 顯示驅動¶
drm/komeda 驅動程式支援 Arm 顯示處理器 D71 及更高版本的產品,本文件簡要概述了驅動程式設計:它的工作原理以及為什麼要這樣設計。
D71 類似顯示 IP 概述¶
從 D71 開始,Arm 顯示 IP 開始採用靈活的模組化架構。顯示管道由多個獨立且功能性的管道階段組成,這些階段稱為元件,每個元件都具有一些特定功能,可以為流動的管道畫素資料提供特定的處理。
典型的 D71 元件
圖層¶
圖層是第一個管道階段,它為下一階段準備畫素資料。它從記憶體中獲取畫素,如果它是 AFBC,則解碼它,旋轉源影像,解包或將 YUV 畫素轉換為裝置內部 RGB 畫素,然後根據需要調整畫素的 color_space。
縮放器¶
顧名思義,縮放器負責縮放,D71 還支援透過縮放器進行影像增強。縮放器的使用非常靈活,可以連線到圖層輸出以進行圖層縮放,或者連線到合成器並縮放整個顯示幀,然後將輸出資料饋送到 wb_layer,然後將其寫入記憶體。
合成器 (compiz)¶
合成器將多個圖層或畫素資料流混合成一個單獨的顯示幀。其輸出幀可以饋送到後圖像處理器以在監視器上顯示,或饋送到 wb_layer 並同時寫入記憶體。使用者還可以在合成器和 wb_layer 之間插入一個縮放器,以首先縮小顯示幀,然後寫入記憶體。
回寫圖層 (wb_layer)¶
回寫圖層執行與圖層相反的操作,它連線到 compiz 並將合成結果寫入記憶體。
後圖像處理器 (improc)¶
後圖像處理器調整幀資料,如伽瑪和色彩空間,以滿足監視器的要求。
時序控制器 (timing_ctrlr)¶
顯示管道的最後階段,時序控制器不是用於畫素處理,而是僅用於控制顯示時序。
合併器¶
與圖層相比,D71 縮放器大多隻有一半的水平輸入/輸出能力,例如,如果圖層支援 4K 輸入大小,則縮放器在同一時間只能支援 2K 輸入/輸出。為了實現完整的幀縮放,D71 引入了圖層分割,它將整個影像分割成兩個半部分,並將它們饋送到兩個圖層 A 和 B,並獨立進行縮放。縮放後,需要將結果饋送到合併器以將兩個部分影像合併在一起,然後將合併後的結果輸出到 compiz。
分割器¶
與圖層分割類似,但分割器用於回寫,它將 compiz 結果分割成兩個部分,然後將它們饋送到兩個縮放器。
D71 管道的可能用法¶
受益於模組化架構,D71 管道可以輕鬆調整以適應不同的用途。D71 有兩個管道,它們支援兩種工作模式
雙顯示模式 兩個管道獨立且分開地工作以驅動兩個顯示輸出。
單顯示模式 兩個管道協同工作以僅驅動一個顯示輸出。
在這種模式下,pipeline_B 不獨立工作,而是將其合成結果輸出到 pipeline_A,其畫素時序也來自 pipeline_A.timing_ctrlr。pipeline_B 的工作方式就像 pipeline_A(主) 的“從屬”
單管道資料流¶
單管道資料流¶
啟用從屬的雙管道¶
啟用從屬管道的資料流¶
輸入和輸出的子管道¶
一個完整的顯示管道可以根據輸入/輸出用途輕鬆地劃分為三個子管道。
圖層(輸入)管道¶
圖層(輸入)資料流¶
圖層分割管道¶
回寫(輸出)管道¶
回寫(輸出)資料流¶
回寫(輸出)分割資料流¶
顯示輸出管道¶
顯示輸出資料流¶
在以下部分中,我們將看到這三個子管道將分別由 KMS-plane/wb_conn/crtc 處理。
Komeda 資源抽象¶
struct komeda_pipeline/component¶
為了充分利用和輕鬆訪問/配置硬體,驅動程式端也使用類似的架構:管道/元件來描述硬體特性和功能,並且特定的元件包括兩個部分
資料流控制。
特定元件的功能和特性。
因此,驅動程式定義了一個公共標頭 struct komeda_component 來描述資料流控制,所有特定元件都是此基本結構的子類。
-
struct komeda_component¶
定義:
struct komeda_component {
struct drm_private_obj obj;
struct komeda_pipeline *pipeline;
char name[32];
u32 __iomem *reg;
u32 id;
u32 hw_id;
u8 max_active_inputs;
u8 max_active_outputs;
u32 supported_inputs;
u32 supported_outputs;
const struct komeda_component_funcs *funcs;
};
成員
obj將元件視為私有物件
pipeline此元件所屬的 komeda 管道
name元件名稱
reg元件暫存器基址,由晶片初始化且僅由晶片使用
id元件 ID
hw_id元件硬體 ID,由晶片初始化且僅由晶片使用
max_active_inputsmax_active_outputs:
可以同時處於活動狀態的最大輸入/輸出數量 注意:該數字不是 supported_inputs 或 supported_outputs 的位數,但可能小於它,因為元件可能不支援同時啟用所有 supported_inputs/輸出。
max_active_outputs最大輸出數量
supported_inputssupported_outputs:
BIT(component->id) 的位掩碼,用於支援的輸入/輸出,描述瞭如何將元件連結到管道中的可能性。
supported_outputs支援的輸出元件 ID 的位掩碼
funcs用於訪問硬體的晶片函式
描述
struct komeda_component 描述瞭如何將元件連結到顯示管道中的資料流功能。所有指定的元件都是此結構的子類。
-
struct komeda_component_output¶
定義:
struct komeda_component_output {
struct komeda_component *component;
u8 output_port;
};
成員
component指示資料來自哪個元件
output_port
描述
一個元件有多個輸出,如果想知道資料來自哪裡,只知道元件是不夠的,我們仍然需要知道它的輸出埠
-
struct komeda_component_state¶
定義:
struct komeda_component_state {
struct drm_private_state obj;
struct komeda_component *component;
union {
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_connector *wb_conn;
void *binding_user;
};
u16 active_inputs;
u16 changed_active_inputs;
u16 affected_inputs;
struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
};
成員
obj透過 drm_atomic_state 跟蹤 component_state
component指向元件的後向指標
{unnamed_union}anonymous
crtc使用者 crtc 的後向指標
plane使用者 plane 的後向指標
wb_conn使用者 wb_connector 的後向指標
binding_user當前繫結的使用者,使用者可以是 crtc、plane 或 wb_conn,這由 component 和 inputs 決定。
圖層:其使用者始終是 plane。
compiz/improc/timing_ctrlr:使用者是 crtc。
wb_layer:wb_conn;
scaler:當輸入是 layer 時為 plane,如果輸入是 compiz 則為 wb_conn。
active_inputsactive_inputs 是 inputs 索引的位掩碼
active_inputs = changed_active_inputs | unchanged_active_inputs
affected_inputs = old->active_inputs | new->active_inputs;
disabling_inputs = affected_inputs ^ active_inputs;
changed_inputs = disabling_inputs | changed_active_inputs;
注意:changed_inputs 不包括所有 active_input,而僅包括 changed_active_inputs,並且此位掩碼可以在晶片級別用於髒更新。
changed_active_inputs已更改的 active_inputs 的位掩碼
affected_inputs受影響的 inputs 的位掩碼
inputs只有在 active_inputs 中設定了 BIT(i) 時,特定的 inputs[i] 才有效,否則 inputs[i] 是未定義的。
描述
component_state 是元件的資料流配置,它是所有特定 component_state 的超類,如 komeda_layer_state、komeda_scaler_state
-
struct komeda_pipeline¶
定義:
struct komeda_pipeline {
struct drm_private_obj obj;
struct komeda_dev *mdev;
struct clk *pxlclk;
int id;
u32 avail_comps;
u32 standalone_disabled_comps;
int n_layers;
struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
int n_scalers;
struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
struct komeda_compiz *compiz;
struct komeda_splitter *splitter;
struct komeda_merger *merger;
struct komeda_layer *wb_layer;
struct komeda_improc *improc;
struct komeda_timing_ctrlr *ctrlr;
const struct komeda_pipeline_funcs *funcs;
struct device_node *of_node;
struct device_node *of_output_port;
struct device_node *of_output_links[2];
bool dual_link;
};
成員
obj將管道連結為 drm_atomic_state 的私有物件
mdev父 komeda_dev
pxlclk畫素時鐘
id管道 ID
avail_comps管道的可用元件掩碼
standalone_disabled_comps停用管道時,某些元件不能與其他元件一起停用,而是需要單獨且獨立的停用。standalone_disabled_comps 是需要單獨停用的元件,並且此概念還引入了兩階段的概念。階段 1:用於停用通用元件。階段 2:用於停用 standalong_disabled_comps。
n_layerslayers 上的圖層數
layers管道圖層
n_scalersscalers 上的縮放器數
scalers管道縮放器
compiz合成器
splitter用於將 compiz 輸出分割成兩個半資料流
mergermerger
wb_layer回寫圖層
improc後圖像處理器
ctrlr時序控制器
funcs晶片私有管道函式
of_node管道 dt 節點
of_output_port管道輸出埠
of_output_links輸出聯結器裝置節點
dual_link如果 of_output_links[0] 和 [1] 都有效,則為 true
描述
表示完整的顯示管道並儲存所有功能元件。
-
struct komeda_pipeline_state¶
定義:
struct komeda_pipeline_state {
struct drm_private_state obj;
struct komeda_pipeline *pipe;
struct drm_crtc *crtc;
u32 active_comps;
};
成員
obj透過 drm_atomic_state 跟蹤 pipeline_state
pipe指向管道的後向指標
crtc當前繫結的 crtc
active_comps位掩碼 - 活動元件的 BIT(component->id)
注意
與管道不同,pipeline_state 不會將任何 component_state 收集到其中。這是因為所有元件都將由 drm_atomic_state 管理。
資源發現和初始化¶
管道和元件用於描述如何處理畫素資料。我們仍然需要 @struct komeda_dev 來描述裝置的整體檢視和裝置的可控制性。
我們有 &komeda_dev、&komeda_pipeline 和 &komeda_component。現在用管道填充裝置。由於 komeda 不僅適用於 D71,而且也適用於以後的產品,因此我們最好在不同的產品之間儘可能多地共享。為了實現這一點,將 komeda 裝置分成兩層:CORE 和 CHIP。
CORE:用於通用特性和功能處理。
CHIP:用於暫存器程式設計和硬體特定特性(限制)處理。
CORE 可以透過三個晶片函式結構訪問 CHIP
struct komeda_pipeline_funcs
struct komeda_component_funcs
-
struct komeda_dev_funcs¶
定義:
struct komeda_dev_funcs {
void (*init_format_table)(struct komeda_dev *mdev);
int (*enum_resources)(struct komeda_dev *mdev);
void (*cleanup)(struct komeda_dev *mdev);
int (*connect_iommu)(struct komeda_dev *mdev);
int (*disconnect_iommu)(struct komeda_dev *mdev);
irqreturn_t (*irq_handler)(struct komeda_dev *mdev, struct komeda_events *events);
int (*enable_irq)(struct komeda_dev *mdev);
int (*disable_irq)(struct komeda_dev *mdev);
void (*on_off_vblank)(struct komeda_dev *mdev, int master_pipe, bool on);
void (*dump_register)(struct komeda_dev *mdev, struct seq_file *seq);
int (*change_opmode)(struct komeda_dev *mdev, int new_mode);
void (*flush)(struct komeda_dev *mdev, int master_pipe, u32 active_pipes);
};
成員
init_format_table初始化
komeda_dev->format_table,此函式應在enum_resource之前呼叫enum_resources用於 CHIP 向 CORE 報告或新增管道和元件資源
cleanup呼叫晶片以清理 komeda_dev->chip 資料
connect_iommu可選,連線到外部 iommu
disconnect_iommu可選,斷開與外部 iommu 的連線
irq_handler用於 CORE 在發生中斷時從 CHIP 獲取硬體事件。
enable_irq啟用 irq
disable_irq停用 irq
on_off_vblank通知硬體開啟/關閉 vblank
dump_register可選,將暫存器轉儲到 seq_file
change_opmode通知硬體切換到新的顯示操作模式。
flush通知硬體重新整理或啟動更新
描述
由晶片級別提供,並由晶片入口函式 xxx_identify 返回,
-
struct komeda_dev¶
定義:
struct komeda_dev {
struct device *dev;
u32 __iomem *reg_base;
struct komeda_chip_info chip;
struct komeda_format_caps_table fmt_tbl;
struct clk *aclk;
int irq;
struct mutex lock;
u32 dpmode;
int n_pipelines;
struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
const struct komeda_dev_funcs *funcs;
void *chip_data;
struct iommu_domain *iommu;
struct dentry *debugfs_root;
u16 err_verbosity;
#define KOMEDA_DEV_PRINT_ERR_EVENTS BIT(0);
#define KOMEDA_DEV_PRINT_WARN_EVENTS BIT(1);
#define KOMEDA_DEV_PRINT_INFO_EVENTS BIT(2);
#define KOMEDA_DEV_PRINT_DUMP_STATE_ON_EVENT BIT(8);
#define KOMEDA_DEV_PRINT_DISABLE_RATELIMIT BIT(12);
};
成員
dev基本裝置結構
reg_basekomeda io 空間的基本地址
chip基本晶片資訊
fmt_tblaclk硬體主引擎 clk
irqirq 編號
lock用於保護 dpmode
dpmode當前顯示模式
n_pipelinespipelines 中的管道數
pipelineskomeda 管道
funcs用於訪問硬體的晶片函式
chip_data晶片資料將由
komeda_dev_funcs.enum_resources()新增,並由komeda_dev_funcs.cleanup()銷燬iommuiommu 域
debugfs_rootkomeda debugfs 的根目錄
err_verbosity用於列印錯誤時要列印多少額外資訊的位掩碼
有關詳細資訊,請參見 KOMEDA_DEV_* 宏。低位元組包含除錯級別類別,高位元組包含額外的除錯選項。
描述
管道和元件用於描述如何處理畫素資料。komeda_device 用於描述裝置的整體檢視和裝置的可控制性。
格式處理¶
-
struct komeda_format_caps¶
定義:
struct komeda_format_caps {
u32 hw_id;
u32 fourcc;
u32 supported_layer_types;
u32 supported_rots;
u32 supported_afbc_layouts;
u64 supported_afbc_features;
};
成員
hw_id硬體格式 ID,硬體特定值。
fourccdrm fourcc 格式。
supported_layer_types指示哪個圖層支援此格式
supported_rots此格式允許的旋轉
supported_afbc_layouts支援的 afbc layerout
supported_afbc_features支援的 afbc 功能
描述
komeda_format_caps 用於描述特定格式的 ARM 顯示特定特性和限制,format_caps 將像 drm_format_info 的擴充套件一樣連結到 komeda_framebuffer 中。
注意
一個 fourcc 可能有兩個不同的 format_caps 項,分別用於 fourcc 和 fourcc+modifier
-
struct komeda_format_caps_table¶
format_caps 管理器
定義:
struct komeda_format_caps_table {
u32 n_formats;
const struct komeda_format_caps *format_caps;
bool (*format_mod_supported)(const struct komeda_format_caps *caps, u32 layer_type, u64 modifier, u32 rot);
};
成員
n_formatsformat_caps 列表的大小。
format_capsformat_caps 列表。
format_mod_supported可選。某些硬體可能具有 format_caps 無法描述的特殊要求或限制,此函式為硬體提供了進行進一步硬體特定檢查的能力。
-
struct komeda_fb¶
使用 komeda 屬性擴充套件 drm_framebuffer
定義:
struct komeda_fb {
struct drm_framebuffer base;
const struct komeda_format_caps *format_caps;
bool is_va;
u32 aligned_w;
u32 aligned_h;
u32 afbc_size;
u32 offset_payload;
};
成員
baseformat_caps為 komeda 特定資訊擴充套件 drm_format_info
is_va如果啟用了 smmu,則為 true
aligned_w對齊的幀緩衝區寬度
aligned_h對齊的幀緩衝區高度
afbc_sizeafbc 的最小大小
offset_payloadafbc 主體緩衝區的開始
將 komeda_dev 附加到 DRM-KMS¶
Komeda 透過管道/元件抽象資源,但 DRM-KMS 使用 crtc/plane/connector。一個 KMS-obj 不能只表示一個元件,因為單個 KMS 物件的要求不能簡單地透過單個元件來實現,通常需要多個元件來滿足要求。例如,為 KMS 設定模式、伽瑪、ctm 所有目標都在 CRTC-obj 上,但 komeda 需要 compiz、improc 和 timing_ctrlr 協同工作才能滿足這些要求。KMS-Plane 可能需要多個 komeda 資源:layer/scaler/compiz。
因此,一個 KMS-Obj 表示 komeda 資源的子管道。
因此,對於 komeda,我們將 KMS crtc/plane/connector 視為管道和元件的使用者,並且在任何時候,管道/元件只能由一個使用者使用。管道/元件將被視為 DRM-KMS 的私有物件;狀態也將由 drm_atomic_state 管理。
如何將 plane 對映到圖層(輸入)管道¶
Komeda 有多個圖層輸入管道,請參見:- 單管道資料流 - 啟用從屬的雙管道
最簡單的方法是將 plane 繫結到固定的圖層管道,但考慮到 komeda 的功能
圖層分割,請參見 圖層(輸入)管道
圖層_分割是一個非常複雜的功能,它將一個大影像分成兩個部分,並分別由兩個圖層和兩個縮放器處理。但是,它在影像中間分割後會匯入邊緣問題或效果。為了避免此類問題,它需要複雜的分割計算和一些特殊的圖層和縮放器配置。我們最好將此類硬體相關複雜性隱藏到使用者模式。
從屬管道,請參見 啟用從屬的雙管道
由於 compiz 元件不輸出 alpha 值,因此從屬管道只能用於底層組合。komeda 驅動程式希望向使用者隱藏此限制。做到這一點的方法是根據 plane_state->zpos 選擇合適的圖層。
因此,對於 komeda,KMS-plane 不表示固定的 komeda 圖層管道,而是具有相同功能的多個圖層。Komeda 將選擇一個或多個圖層以滿足一個 KMS-plane 的要求。
使元件/管道成為 drm_private_obj¶
將 drm_private_obj 新增到 komeda_component、komeda_pipeline
struct komeda_component {
struct drm_private_obj obj;
...
}
struct komeda_pipeline {
struct drm_private_obj obj;
...
}
透過 drm_atomic_state 跟蹤 component_state/pipeline_state¶
將 drm_private_state 和 user 新增到 komeda_component_state、komeda_pipeline_state
struct komeda_component_state {
struct drm_private_state obj;
void *binding_user;
...
}
struct komeda_pipeline_state {
struct drm_private_state obj;
struct drm_crtc *crtc;
...
}
komeda 元件驗證¶
Komeda 有多種型別的元件,但驗證過程類似,通常包括以下步驟
int komeda_xxxx_validate(struct komeda_component_xxx xxx_comp,
struct komeda_component_output *input_dflow,
struct drm_plane/crtc/connector *user,
struct drm_plane/crtc/connector_state, *user_state)
{
setup 1: check if component is needed, like the scaler is optional depending
on the user_state; if unneeded, just return, and the caller will
put the data flow into next stage.
Setup 2: check user_state with component features and capabilities to see
if requirements can be met; if not, return fail.
Setup 3: get component_state from drm_atomic_state, and try set to set
user to component; fail if component has been assigned to another
user already.
Setup 3: configure the component_state, like set its input component,
convert user_state to component specific state.
Setup 4: adjust the input_dflow and prepare it for the next stage.
}
komeda_kms 抽象¶
-
struct komeda_plane¶
drm_plane 的 komeda 例項
定義:
struct komeda_plane {
struct drm_plane base;
struct komeda_layer *layer;
};
成員
baselayer表示此 plane 的可用圖層輸入管道。
注意:該圖層不是針對特定圖層,而是指示一組具有相同功能的圖層。
-
struct komeda_plane_state¶
定義:
struct komeda_plane_state {
struct drm_plane_state base;
struct list_head zlist_node;
u8 layer_split : 1;
};
成員
basezlist_nodezorder 列表節點
layer_split開啟/關閉 layer_split
描述
plane_state 可以分成兩個資料流(左/右),並由兩個圖層 komeda_plane.layer 和 komeda_plane.layer.right 處理
-
struct komeda_wb_connector¶
定義:
struct komeda_wb_connector {
struct drm_writeback_connector base;
struct komeda_layer *wb_layer;
};
成員
basewb_layer表示 komeda 的關聯回寫管道
-
struct komeda_crtc¶
定義:
struct komeda_crtc {
struct drm_crtc base;
struct komeda_pipeline *master;
struct komeda_pipeline *slave;
u32 slave_planes;
struct komeda_wb_connector *wb_conn;
struct completion *disable_done;
struct drm_encoder encoder;
};
成員
basemaster只有 master 具有顯示輸出
slave可選
沒有自己的顯示輸出,處理的資料流將合併到 master 中。
slave_planeskomeda 從屬 plane 掩碼
wb_connkomeda 回寫聯結器
disable_done此 flip_done 用於跟蹤停用
encoder管道末端的編碼器
-
struct komeda_crtc_state¶
定義:
struct komeda_crtc_state {
struct drm_crtc_state base;
u32 affected_pipes;
u32 active_pipes;
u64 clock_ratio;
u32 max_slave_zorder;
};
成員
baseaffected_pipes一次顯示例項中受影響的管道
active_pipes一次顯示例項中活動的管道
clock_ratio(aclk << 32)/pxlclk 的比率
max_slave_zorder從屬 zorder 的最大值
komde_kms 函式¶
-
int komeda_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)¶
構建顯示輸出資料流
引數
struct drm_crtc *crtcDRM crtc
struct drm_atomic_state *statecrtc 狀態物件
描述
crtc_atomic_check 是最終檢查階段,因此除了根據 crtc_state 構建顯示資料管道之外,還需要釋放或停用未宣告的管道資源。
返回
成功返回零,失敗返回 -errno
-
int komeda_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)¶
構建輸入資料流
引數
struct drm_plane *planeDRM plane
struct drm_atomic_state *stateplane 狀態物件
返回
成功返回零,失敗返回 -errno
將 komeda 構建為 Linux 模組驅動程式¶
現在我們有兩個級別的裝置
komeda_dev:描述真實的顯示硬體。
komeda_kms_dev:將 komeda_dev 附加或連線到 DRM-KMS。
所有 komeda 操作都由 komeda_dev 或 komeda_kms_dev 提供或操作,模組驅動程式只是一個簡單的包裝器,用於將 Linux 命令(probe/remove/pm)傳遞到 komeda_dev 或 komeda_kms_dev。