MIPI DIsplay Panel And Linux Driver Model【轉】


轉自:https://blog.csdn.net/redredbird/article/details/12648847

硬件篇
架構
最近研究MIPI DSI Panel Linux Driver架構,於是一邊啃spec性質的官方文檔,一邊從dri-devel,omap-linux等郵件列表里,搜索所有的跟panel driver相關的討論,盡力在短時間內把整個subsystem的脈絡迅速掌握。

MIPI規范不止於display,也包括camera(MIPI CSI),電源管理,射頻的東西。和Display相關的就是MIPI DSI,DPI,DBI等,規范了host display controller到panel之間通信時從物理層,鏈路層到應用層的協議。目標市場是對功耗、屏幕尺寸有特殊要求的移動設備,不同於VESA針對PC市場。

大而籠統地說,mobile display system一般可分為兩種 architecture:

 

 

 

右邊這種叫“smart panel”,左邊這種叫"dumb panel"(“啞”屏)。區別是smart panel帶framebuffer,“刷屏”操作由屏自己來負責,host controller成了甩手掌櫃,而啞屏就和任何一種非主動設備一樣,可以把它當作一塊帶有簡單時許控制電路的玻璃。

mipis在上面兩種基本architecture的基礎上,擴展了四種架構。

Type1
完全的command模式,mipi規范里DBI屬於這種type。

 

 

 

Type2
由type1的一條control-interface接口變為了video-interface + control-interface的組合,full-framebuffer也變為了partial-framebuffer,因為沒有了full-framebuffer,所以不可能完全依靠panel來刷屏,這就是video-interface存在的必要;但partial-framebuffer也為panel帶來了partial-update的靈活性。

 

 

 

control-interface和video-interface可能是在同一個物理總線上的。這里的control-interface類似I2C或者PCI,video-interface傳遞pixels/clock。control-interface都是傳遞one-shot的data/command,有請求有應答;video-interface傳遞continuous的data,不需要slave device的應答。Linux的設備驅動模型樹總是圍繞control-interface來組織的。master同slave之間的連接組織成樹,內核電源管理子系統通過遍歷樹來得到一個正確的suspend/resume的順序,否則會產生很多ordering issue;通過control-interface,master可以讀寫slave的寄存器,讀寫片上存儲內容,向slave發送控制命令等。如下圖我的電腦里顯示的smbus控制器和掛在其上的i2c從設備的樹狀圖:

 

 

 

樹上0000:00:14:00的pci節點就是smbus控制器的設備對象,下面的i2c-0和i2c-1節點分別是掛在這顆i2c總線上的兩個i2c從設備(比如某種傳感器)。扯遠了,繼續回到DSI上面。

Type3
徹底沒有了panel-framebuffer,但還保留有control-interface。這樣video-interface和control-interface仍然共用一條physical line,master設備仍然不需要借助其他多余的pin就可以控制panel。為了支持panel可以通過control-interface的命令來控制,panel內部所以還需要保留寄存器。

 

 

 

Type 4
用犧牲更多的引腳數目(control lines)的代價來簡化Panel內部的設計,不再需要內置寄存器。

 

 

 

MIPI規范定義的三種display接口協議,DBI,DPI,DSI。其中DBI可以實現上面4中type的controlinterface,DPI可以實現videointerface。而DSI最靈活,單純的工作在commandmode可以實現type1,command+videomode共用時可以實現type2/3,單純的工作在videomode時可以實現type4。對於type4,controlline可以是固定的gpio配置等。

DSI物理層
物理層上面的DSI有三種工作模式,control-mode,escape-mode和highspeed-mode。

硬件reset后首先進入的lower-power stop state默認就是在control-mode,host當需要以burst的方式在總線上發送數據時(比如像素數據或者DCS),就要讓總線進入high-speed mode。

DataLane上隨即會出現SoT(startof transmision)和EoT信號,分別是進入和離開highspeed mode的標記,在一對SoT和EoT之間夾着一個或多個sPa(shortpacket)或者lPa(longpacket)。

escape-mode是一種特殊地允許DSI總線能在低速低功耗狀態下發送數據的模式,在escape-mode下還可以主動切換到耗電更低的超低功耗模式。

因為DSI的控制命令的傳輸是雙向的,雙向傳輸的機制由host和panel之間通過bus-turnaround協議用作為交換使用總線所有權的“令牌”。

下圖中BTA就用作panel向host響應讀請求,使用escape-mode下的LPDT命令在低功耗總線下傳輸packet的情景

 

 

 


設備電源狀態轉換
MIPIDCS規范了一系列電源狀態,簡單的說,有

1).Sleep on/off:除了和host的link-interface保持正常工作電源狀態以外,其他模塊都處於低功耗模式。(因為hostdisplay需要通過linkinterface來喚醒paneldevice,所以這個不能關)

2).Normal/Idlemode:panel使用正常的像素顏色位深或者使用有限位數的顏色位深,因為video模式的Panel的像素都是來自於host,而command-mode的panel像素來自自身的framebuffer,所以idle-mode只對command-mode的Panel有效

3).Paritial mode:只針對command-mode的panel有效,即只顯示framebuffer指定矩形區域的像素。

 

軟件篇
MIPI DSI Panel需要單獨的軟件支持嗎?首先,DSI是一種chip-to-chip的接口,不同於HDMI, DP這種box-to-box的接口,不同的芯片商,可能都有自己的不同於別家的上下電或初始化序列;其次,即使同樣可以作為chip-to-chip接口的eDP,也有我稱之為自配置的功能,可以通過EDID/AUX等獲得panel支持的Mode和timing;而再‘標准’的DSI panel也要硬編碼許多panel相關的參數。

panel driver屬於Linux/Android display stack的“最后一公里”,PC上的display stack是DRM/KMS子系統,Android的mobile display stack子系統是framebuffer。Mobile display stack提供的用戶服務並不復雜,主要就是打開/關閉,不像pc的stack還可以改變mode和timing,因為mobile display的mode和timing一般都是固定的,由LCD模組廠商決定。

相關的一些內核/用戶接口通過/sys提供,比如在我的聯想a790e手機的adb shell環境中執行命令:

# echo 1 > /sys/devices/virtual/graphics/fb0/blank
即可看到手機只剩背光了,這時display controller給panel的pixel/clock信號被切斷或者被‘blank’:

 

 

不光pixel和clock被切斷,可能整個信號鏈條上的block的power和clk也被關閉了以達到更省電的效果

再往fb0這個節點的blank屬性寫0時才重新打開panel

# echo 0 > /sys/devices/virtual/graphics/fb0/blank

 

 

 

其實整個過程同我們按下手機頂部的電源鍵display stack所觸發的動作是一樣的,只是后者還把背光驅動給關掉了而已,所以整個屏都是“黑色”。

display soc在硬件上,從framebuffer到panel的video stream流會經過一條pipeline,這條pipeline一般由plane,controller,encoder,panel組成。最前端的plane為多個head的機制提供了單獨的framebuffer支持,不同的plane(圖層)可以接入不同的display device如hdmi,dsi,vga顯示不同的內容;controller負責從framebuffer中的指定區域讀取像素,驅動各種需要的PLL,時鍾(pixel clock等),如果controller支持多個overlay,controller還要管理overlay的疊加工作;encoder負責將並行的pixel/clock信號轉換為終端顯示設備需要的串行信號等如DSI,HDMI,最后的panel則是接收輸入的pixel/clock信號驅動行列驅動器在玻璃上‘顯示’圖像,如圖:

 

 

+-------------------------------------------------+
| +------------+ +-----------+ +------------+ | +-----------+
| | | | Display | | Encoder | | | |
| | Plane +---+ Controller+---+ (HDMI,DSI) +-+-+ Panel |
| | | | | | | | | |
| +------------+ +-----------+ +------------+ | +-----------+
+-------------------------------------------------+
這些block除了最后的panel屬於external device以外,其他都以ip的形式集成到主控制器的soc里了,同一系列的芯片不同版本的soc可能只是對不同版本的ip block的組合而已,所以,為了代碼復用,一般soc vendor的driver在設計時為每個block都設計了自己的驅動對象struct device_driver和由該驅動管理的設備類struct deice的定義,具體的設備實例然后被板級的bringup code動態地‘注冊’進系統,driver在probe它們時為其分配必要的資源和注冊各自的hook callback函數,比如響應上面的用戶對blank屬性設置的請求的on/off函數。pipeline也決定了控制函數的調用順序,比如on/off處理函數,在on系統請求被調用時,就要先調用最上級的plane_on_callback,最后調用最下級的panel_on_callback;如果是off系統請求時,順序就完全相反。

板級bringup code注冊設備的方法有很多,比如在a790e上,在Kernel boot cmdline:

 

 

 

可以看到lcd.name=mipi_video_nt35510_bitland_wvga參數。而在kernel boot時實現了panel driver的module會在module_init()時檢查該boot參數,所以只有nt35510_bitland_wvga的panel driver會創建nt35510的panel platform_device。

在基於msm7627a soc的設備a790e的display driver stack中,一條mipi dsi的display pipeline有如下driver對象會被涉及:

msm_fb driver,match的設備對象的名字是“msm_fb”,映射的是plane block

static struct platform_driver msm_fb_driver = {
.probe = msm_fb_probe,
.remove = msm_fb_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = msm_fb_suspend,
.resume = msm_fb_resume,
#endif
.shutdown = NULL,
.driver = {
/* Driver name must match the device name added in platform.c. */
.name = "msm_fb",
.pm = &msm_fb_dev_pm_ops,
},
};
mdp driver,Match的設備對象名為‘msm_mdp’,對應的是display controller block

static struct platform_driver mdp_driver = {
.probe = mdp_probe,
.remove = mdp_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = mdp_suspend,
.resume = NULL,
#endif
.shutdown = NULL,
.driver = {
/*
* Driver name must match the device name added in
* platform.c.
*/
.name = "mdp",
.pm = &mdp_dev_pm_ops,
},
};
mipi_dsi driver, match的設備對象名為“mipi_dsi”,對應的是dsi encoder block
static struct platform_driver mipi_dsi_driver = {
.probe = mipi_dsi_probe,
.remove = mipi_dsi_remove,
.shutdown = NULL,
.driver = {
.name = "mipi_dsi",
},
};
具體的panel driver,這里我沒有a790e上NT35510 panel的源代碼,但和其他的都差不多
static struct platform_driver this_driver = {
.probe = mipi_novatek_lcd_probe,
.driver = {
.name = "mipi_novatek",
},
};
這些driver所管理的設備對象就組成一條display pipeline各自所需track的state。
在msm7627a的driver設計中,每個獨立的head就有這么一條pipeline,從/sys中我們可以看到:

 

 

 

從device name后面的device id可以看到它們是屬於一組的:524801=($(MIPI_VIDEO_PANEL) << 16) | 513);MIPI_VIDEO_PANEL= 8;

如果從soc接出兩條pipe分別驅動兩個不同的panel顯示不同的內容,那么還會創建出另一組設備對象來管理它們,可以當作以樹形式在組織,雖然/sys/device/下面並不是這么組織的:

+--+--- msm_fb.xxx
| |
| +--- mdp.xxx
| |
| +--- mipi_dsi.xxx
| |
| +--- mipi_first_panel.xxx
|
+--+--- msm_fb.yyy
| |
| +--- mdp.yyy
| |
| +--- mipi_dsi.yyy
| |
| +--- mipi_second_panel.yyy
|
display driver stack的各個block的device對象必須要有一定的probe順序,比如在mipi_dsi設備被probe之前,mipi_panel設備就要先被創建和probe,因為在注冊on/off調用鏈時上一級(upstream)的設備probe函數需要知道下一級(downstream)的設備對象
————————————————
版權聲明:本文為CSDN博主「redredbird」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/redredbird/article/details/12648847


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM