【ATU Book-i.MX8系列】 NXP i.MX8M Mini DRM driver解析(Part 2)

關鍵字 :NXPi.MX8M Mini
1. 萬事俱備
  • 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 進行綁定


        以我們舉的例子來看,會呼叫的 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 好處於可等待上層指令的狀態。

  • CRTC 的 lcdif_crtc_bind()


  • drm_crtc 初始化,其中就包括了 plane、mode config function 等設定

        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 也完成它們的初始化等待上層指令。

  • Encoder 的 imx_sec_dsim_bind(),選用 DRM_MODE_ENCODER_DSI,並開始嘗試進行 bridge bind


  • bridge 的 bind function 會重複執行直到連接到 Connector 為止,被找到的 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_fbdev_cma_init() 裡面,
  1. 首先會進行 CRTC 還有 Connector 的綁定,分別實作在 drm_fb_helper_init() 還有 drm_fb_helper_single_add_all_connectors() function
  2. 有了這個基礎,接下來會呼叫 drm_fb_helper_initial_config() 進行 best mode 的選定跟 fbdev 的創建。



  • drm_fb_helper_initial_config(),可分解為 CRTC 的設置以及 drm frame buffer 的建立。



  • drm_setup_crtcs() 會設置好每一個 CRTC,方法是從每個 Connector 得到所有的 mode,並以此為每一個 CRTC 挑選計算出來分數最好的,建立出一個 CRTC 跟 Connector 之間的 mapping。
  • drm_fb_helper_single_fb_probe() 則會初始化 drm_framebuffer,其過程與一般的 Frame Buffer初始化過程差不多,最後呼叫 register_framebuffer() 完成 Frame Buffer 的註冊之後,Frame Buffer 就可以使用了。

 

  • 小結

        流程至此,已經完成 DRM 子系統的初始化過程。表示 DRM driver 已經 ready 等待上層使用,所以在下一章節會簡單介紹上層如何使用 DRM。



2. DRM 應用程式開發

        這個章節將說明如何開發一個 DRM 應用程式。關於應用程式與 kernel space 之間的交互關係,其實我們在 Chapter 1.3 有提到一點點,我們再把以下這張架構圖拿出來複習一下。這張架構圖說明了,在 user space 的應用程式會透過 libdrm 間接對 kernel space 進行 ioctrl 操作。而一般的 DRM 應用程式需要包含的基本內容有,

  1. open("/dev/dri/card0")

        最基本的 open file node 取得 handle。

 

  1. drmModeGetResources(...)

        利用 DRM_IOCTL_MODE_GETRESOURCES,取得 CRTC、Encoder、Connector 等 ID 以及個數。

 

  1. drmModeGetConnector(...)

        利用上式內容,DRM_IOCTL_MODE_GETCONNECTOR 可取得 Connector 真實的資訊,包含 modes setting。

 

  1. DRM_IOCTL_MODE_CREATE_DUMBdrmModeAddFB(...)drmIoctl(DRM_IOCTL_MODE_MAP_DUMB)mmap(...)

        以上 function 可建立一個 dumb framebuffer 並完成映射。

 

  1. drmModeSetCrtc(crtc_id, fb_id, connector_id, mode)

        設定 CRTC 並連接到 dumb framebuffer,開始進行螢幕顯示。

 

        基於上面的架構,我們在網路上找到一個範例程式,single buffer。這隻範例程式建立一個 dumb framebuffer,內容全部都是 0xFF(也就是白色),並把它顯示到螢幕上。參考範例程式碼連結以及實際上執行的結果如下:

https://blog.csdn.net/hexiaolong2009/article/details/83721242



0. 前提需要先關掉占用 DRM 的 device



此時,螢幕無輸出變為黑色,


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. 參考文件

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論