- Bring Up Master
上一篇文章提到,bring up master 的條件是所有的子元件都匹配成功。滿足此條件之後,會呼叫 master 的 imx_drm_ops 的 bind function。在這個 imx_drm_bind() 裡面除了會初始化〝mode config〞以及〝vblank〞,更重要的,因為子元件都已經準備好了,所以有辦法將所有的子元件綁定在一起。就在 component_bind_all() 裡面,會逐一掃過所有的 match 的元件,呼叫其各自的 bind function,讓 master 與子元件建立交互關係。最後,會初始化 fbdev(drm_fbdev_cma_init())完成 DRM 子系統的初始化過程。
|
以我們舉的例子來看,會呼叫的 bind function 有兩個,一個是 CRTC 的 lcdif_crtc_bind(),還有另一個是 Encoder 的 imx_sec_dsim_bind()。
CRTC 主要負責接收來自多個 drm_plane 的 pixel data,並將它們做好疊圖的處理。另外也負責 maintain drm_display_mode,讓 panel 有正確的 resolution 以及 timing 的設定。下一步這些 pixel data 就可以餵給 drm_encoder 做下一步的處理。所以,lcdif_crtc_bind() 所進行的 drm_crtc 初始化,其中就包括了 plane、mode config function 等設定,完成之後的 CRTC 就 ready 好處於可等待上層指令的狀態。
|
Encoder 主要連接 drm_crtc 跟 drm_connector,負責將 CRTC 過來的 pixel data 轉換成適合 Connector 的格式,再交給 Connector。所以在 imx_sec_dsim_bind() 裡,因為底層連接的介面是 MIPI DSI,所以自然就會選用 type 為 DRM_MODE_ENCODER_DSI 的 codec 為 drm_encoder 進行初始化。
另外,有一個子元件〝bridge〞前面沒有提到,是一個鏈狀的結構,可以視為 Encoder 的延伸,最終才會接到 Connector(panel)。因此,會進行延伸 bridge 的 bind function,而且此動作會重複直到連接到 Connector 為止。在 Connector 完成 drm_connector_init()、drm_mode_connector_attach_encoder()、還有 drm_panel_attach() 之後,Encoder 跟 Connector 也完成它們的初始化等待上層指令。
|
Frame Buffer 主要功能為提供一塊記憶體來儲存要秀出的圖像資料,而 DRM 的 Frame Buffer 是由 GEM 來管理。在談 drm_framebuffer 之前,系統需要開啟 CONFIG_DRM_FBDEV_EMULATION 的功能。開啟這個功能後,表示 DRM 將可以模擬一個 Frame Buffer 設備,如此上層便可使用基於 fbdev 的顯示框架。於是乎,drm_framebuffer 的初始化,drm_fbdev_cma_init(),這個 function 也成為我們最後一個在 imx_drm_bind() 裡面要分析的。
|
- 小結
流程至此,已經完成 DRM 子系統的初始化過程。表示 DRM driver 已經 ready 等待上層使用,所以在下一章節會簡單介紹上層如何使用 DRM。
2. DRM 應用程式開發
這個章節將說明如何開發一個 DRM 應用程式。關於應用程式與 kernel space 之間的交互關係,其實我們在 Chapter 1.3 有提到一點點,我們再把以下這張架構圖拿出來複習一下。這張架構圖說明了,在 user space 的應用程式會透過 libdrm 間接對 kernel space 進行 ioctrl 操作。而一般的 DRM 應用程式需要包含的基本內容有,
- open("/dev/dri/card0")
最基本的 open file node 取得 handle。
- drmModeGetResources(...)
利用 DRM_IOCTL_MODE_GETRESOURCES,取得 CRTC、Encoder、Connector 等 ID 以及個數。
- drmModeGetConnector(...)
利用上式內容,DRM_IOCTL_MODE_GETCONNECTOR 可取得 Connector 真實的資訊,包含 modes setting。
- DRM_IOCTL_MODE_CREATE_DUMB、drmModeAddFB(...)、drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)、mmap(...)
以上 function 可建立一個 dumb framebuffer 並完成映射。
- drmModeSetCrtc(crtc_id, fb_id, connector_id, mode)
設定 CRTC 並連接到 dumb framebuffer,開始進行螢幕顯示。
基於上面的架構,我們在網路上找到一個範例程式,single buffer。這隻範例程式建立一個 dumb framebuffer,內容全部都是 0xFF(也就是白色),並把它顯示到螢幕上。參考範例程式碼連結以及實際上執行的結果如下:
https://blog.csdn.net/hexiaolong2009/article/details/83721242 此時,螢幕無輸出變為黑色, 1. 執行測試程式 ./modeset-single-buffer 此時,螢幕輸出 dumb framebuffer 內容,0xFF,為白色, |
- 小結
以上我們整篇文章從 device tree 開始,一路介紹到 kernel space 的 DRM driver 的初始化流程,然後更進一步完成 user space 的 DRM 應用程式範例。從下到上,對於 Linux Display 可說是有了一個整體性的概念,基於此概念往上延伸不論是 Android 的 display 子系統或是 Wayland等 framework 可說是打下了深厚的基礎。因此,各位開發者在未來遇到 display 的問題時,對於如何排錯就擁有了一個好的起手式,不至於毫無頭緒。完成 DRM 之後,後續我們將繼續深究其它在 i.MX8M Mini 上的 Linux driver,一塊一塊的組合出整個 i.MX8M Mini EVK 指日可待。TBC…
3. 參考文件
- 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
評論