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(主) 的“從屬”

單管道資料流

Single pipeline digraph

單管道資料流

啟用從屬的雙管道

Slave pipeline digraph

啟用從屬管道的資料流

輸入和輸出的子管道

一個完整的顯示管道可以根據輸入/輸出用途輕鬆地劃分為三個子管道。

圖層(輸入)管道

Layer data digraph

圖層(輸入)資料流

Layer Split digraph

圖層分割管道

回寫(輸出)管道

writeback digraph

回寫(輸出)資料流

split writeback digraph

回寫(輸出)分割資料流

顯示輸出管道

display digraph

顯示輸出資料流

在以下部分中,我們將看到這三個子管道將分別由 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_inputs

max_active_outputs:

可以同時處於活動狀態的最大輸入/輸出數量 注意:該數字不是 supported_inputssupported_outputs 的位數,但可能小於它,因為元件可能不支援同時啟用所有 supported_inputs/輸出。

max_active_outputs

最大輸出數量

supported_inputs

supported_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

的輸出埠 komeda_component_output.component

描述

一個元件有多個輸出,如果想知道資料來自哪裡,只知道元件是不夠的,我們仍然需要知道它的輸出埠

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

當前繫結的使用者,使用者可以是 crtcplanewb_conn,這由 componentinputs 決定。

  • 圖層:其使用者始終是 plane。

  • compiz/improc/timing_ctrlr:使用者是 crtc。

  • wb_layer:wb_conn;

  • scaler:當輸入是 layer 時為 plane,如果輸入是 compiz 則為 wb_conn。

active_inputs

active_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_statekomeda_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_layers

layers 上的圖層數

layers

管道圖層

n_scalers

scalers 上的縮放器數

scalers

管道縮放器

compiz

合成器

splitter

用於將 compiz 輸出分割成兩個半資料流

merger

merger

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_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_base

komeda io 空間的基本地址

chip

基本晶片資訊

fmt_tbl

komeda_dev_funcs->init_format_table 初始化

aclk

硬體主引擎 clk

irq

irq 編號

lock

用於保護 dpmode

dpmode

當前顯示模式

n_pipelines

pipelines 中的管道數

pipelines

komeda 管道

funcs

用於訪問硬體的晶片函式

chip_data

晶片資料將由 komeda_dev_funcs.enum_resources() 新增,並由 komeda_dev_funcs.cleanup() 銷燬

iommu

iommu 域

debugfs_root

komeda 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,硬體特定值。

fourcc

drm 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_formats

format_caps 列表的大小。

format_caps

format_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;
};

成員

base

drm_framebuffer

format_caps

為 komeda 特定資訊擴充套件 drm_format_info

is_va

如果啟用了 smmu,則為 true

aligned_w

對齊的幀緩衝區寬度

aligned_h

對齊的幀緩衝區高度

afbc_size

afbc 的最小大小

offset_payload

afbc 主體緩衝區的開始

將 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_componentkomeda_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_statekomeda_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;
};

成員

base

drm_plane

layer

表示此 plane 的可用圖層輸入管道。

注意:該圖層不是針對特定圖層,而是指示一組具有相同功能的圖層。

struct komeda_plane_state

定義:

struct komeda_plane_state {
    struct drm_plane_state base;
    struct list_head zlist_node;
    u8 layer_split : 1;
};

成員

base

drm_plane_state

zlist_node

zorder 列表節點

layer_split

開啟/關閉 layer_split

描述

plane_state 可以分成兩個資料流(左/右),並由兩個圖層 komeda_plane.layerkomeda_plane.layer.right 處理

struct komeda_wb_connector

定義:

struct komeda_wb_connector {
    struct drm_writeback_connector base;
    struct komeda_layer *wb_layer;
};

成員

base

drm_writeback_connector

wb_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;
};

成員

base

drm_crtc

master

只有 master 具有顯示輸出

slave

可選

沒有自己的顯示輸出,處理的資料流將合併到 master 中。

slave_planes

komeda 從屬 plane 掩碼

wb_conn

komeda 回寫聯結器

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;
};

成員

base

drm_crtc_state

affected_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 *crtc

DRM crtc

struct drm_atomic_state *state

crtc 狀態物件

描述

crtc_atomic_check 是最終檢查階段,因此除了根據 crtc_state 構建顯示資料管道之外,還需要釋放或停用未宣告的管道資源。

返回

成功返回零,失敗返回 -errno

int komeda_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state)

構建輸入資料流

引數

struct drm_plane *plane

DRM plane

struct drm_atomic_state *state

plane 狀態物件

返回

成功返回零,失敗返回 -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。