- 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
參考來源