- 簡介
在早期的 Linux display 子系統中,我們常以 FB(Frame Buffer)做為主要的框架;只要有一個 Frame Buffer,我們就可以在顯示屏幕上秀出各種資訊。但隨著硬體不斷的快速演進,DRM(Direct Rendering Manager)更能配合硬體的功能,相比之下,FB 就顯得不足以應付現有的需求。比方說,FB 不支援 overlay 的概念、不支援 hw cursor … 等等,這些以往都得在 user space 操作。所以現今 Linux 平台上開發的研發人員,已經開始使用 DRM 來取代 FB,就是因為 DRM 子系統在 kernel space 都可以幫忙處理這些事情,從下圖可以簡單看出,FB 以及 DRM 之間在架構上主要的差異。
而本文將以 i.MX8M Mini EVK 平台,介紹 DRM driver 是如何把 MIPI DSI panel 或是 MIPI DSI to HDMI bridge 註冊上子系統並且將整個 display 子系統 bring up 的整個過程。了解這部分可以幫忙開發人員在初期還點不亮 panel 的情況下,更有系統的看懂 log 上所提示的錯誤並且有效的進行 debug。
FB vs. DRM(參考文件 I.) |
- 名詞解釋
|
- 軟體架構
接下來看一下 DRM 的軟體架構。在用戶空間,DRM 與其他 driver 不同,它把自己封裝成了一個 libdrm,取代一般常用的 IOCTL,藉此來提供使用者更方便更直覺的操作。後面的章節我們會簡單介紹一個 app,示範如何利用 libdrm 進行圖像顯示的一連串操作。
另一方面,在 kernel 端 DRM driver 分為兩大塊,一個是 GEM(Graphics Execution Manager),負責提供 Frame Buffer 的記憶體管理,這也是 GPU 會利用到 DRM 的地方。GEM 在本文中暫時不會提到太多;另一個是 KMS(Kernel Mode Setting),負責選擇並設置所連接的螢幕本身提供的所謂的〝mode〞,這些設定包括 resolution、color depth 以及 refresh rate。這部分將會是本文的重點,在後面的章節裡面我們會細談。
DRM SW arch from Wiki
|
- 小結
綜合以上三個小章節,另外補充說明一下所謂的 KMS 就是由 CRTC、Planes、Encoder、Connector 所組成,所以整個架構就可以串起來了。而 KMS 利用這幾個元件的相互合作,達到 mode setting 的功用。如果再進一步說明,所謂的 mode setting 做的事情就是〝更新畫面〞和〝設定 display 參數〞。
- 更新畫面 :page-flip、overlay
- 設定 display 參數 :resolution、color depth、refresh rate
2. Linux DRM driver 解析
- Superdevice
DRM 類似 ALSA 是一個牽扯到許多子元件所組成的顯示子系統,所以會以〝顯示卡〞來做表示。而這張代表著整個子系統的顯示卡在 device tree 會以一個 superdevice(display-subsystem) 展現,如下面程式碼所示,並以此管理著所有的子元件。每一個新加入的子元件都會被檢視是否匹配,最後當 superdevice 收集到所有的子元件之後,便會觸發一連串初始化的動作來綁定並帶起整個顯示子系統。
|
- 建立 master(imx_drm_core)
Superdevice 的 probe function 可參考下圖,透過 drm_of_component_probe_with_match() 可以將 CRTC 以及它有效的 remote endpoint 都添加到 match list 上。如果從 device tree 來查看,在這個例子裡面,CRTC 就是 lcdif,而它有效的 remote endpoint 是 dsim_from_lcdif,所以 lcdif 以及 dsim_from_lcdif 都會被加在 match list 裡面。另外,在這個 probe function 裡面,最後會呼叫 component_master_add_with_match() 來建立一個 master,之前的 match list 也會儲存在 master 裡,並且呼叫 try_to_bring_up_master() 嘗試做第一次 bring up。每一次的 bring up 不一定會成功,在此之後的每一個子元件加入都會重新呼叫 try_to_bring_up_master() 嘗試進行 bring up 動作,但是只有當所有的子元件都 ready 了之後,master 才會被 bring up。
- 前半段以 superdevice device tree 裡的 ports 綁定 crtc,並加入到 match list 中
- 後半段可搭配下面 device tree,remote endpoint 為 dsim_from_lcdif,同樣加入 match list 中
- 最後嘗試 bring up master
- 新增 Encoder – i.MX MIPI DSI Host Controller(sec_mipi_dsim-imx)
此小節新增 MIPI DSI Host,它在 device tree 的結構可參考如下。一端與角色為 CRTC 的 lcdif 連接,另一端列舉兩個例子,一個是在原廠預設的 dts 裡可以看到 adv7535,所以可以與 HDMI panel 連接;另一個範例連接了一片 MIPI DSI 的 panel,不論是哪一種選擇,都可以看得出來 MIPI DSI Host 的位置是一個 Encoder 的角色。
選擇 1:fsl-imx8mm-evk-rm67191.dts,對接一片 MIPI DSI panel: 選擇 2:原廠預設 fsl-imx8mm-evk.dts,對接 adv7535 bridge,可以連接 HDMI panel。 |
再來看 mipi dsi 的 driver,sec_mipi_dsim-imx 的 probe function 會呼叫 component_add() 將 device 加入 component list 裡面,並且如前面章節所描述的,使用 try_to_bring_up_masters() 來嘗試 bring up master。
- 新增 CRTC – LCDIF DRM CRTC(lcdif-crtc)
同理,不過此小節新增的是 CRTC,它在 device tree 的結構可參考如下,它會與角色為 Encoder 的 mipi_dsi 連接,這也呼應前面小節所談到的。
另外,driver 的部分也是同前一小節,lcdif-crtc 的 probe function 會呼叫 component_add() 將 device 加入 component list 裡面,並嘗試 bring up master。但不同的是,這裡因為 match 與 component 在 find_components() 裡發現匹配成功,所以會進行 bring up master,呼叫 master 的 imx_drm_ops 的 bind function。
|
3. 未完待續
這篇博文簡單的介紹了 DRM driver 的準備工作,真正的重頭戲還在後面。備好了這些子元件之後,DRM driver 是如何使這些元件互相綁定完成初始化,進而寫一支測試程式來做一個簡單的繪圖並顯示等等之類的內容,我們將在下一篇博文裡繼續介紹。
4. 參考文件
- https://events.static.linuxfound.org/sites/events/files/slides/brezillon-drm-kms.pdf
- https://blog.csdn.net/hexiaolong2009/category_9281458.html
- https://blog.csdn.net/qq_33487044/category_8454463.html
- DRM wiki (https://en.wikipedia.org/wiki/Direct_Rendering_Manager)
- Linux DRM 原始碼
- http://betteros.org/tut/graphics1.php
評論