Tina Linux LCD調試指南
1 概述
編寫目的 本文檔將介紹sunxi 平臺Display Engine 模塊中LCD 的調試方法。
LCD 調試方法,調試手段。
LCD 驅動編寫。
lcd0 節點下各個屬性的解釋。
典型LCD 接口配置。
適用范圍:sunxi 平臺DE1.0/DE2.0 中LCD 屏幕參數設置。
2 相關術語介紹
?
表2-1: LCD 相關術語
?
術語 | 解釋說明 |
---|---|
SUNXI | Allwinner 一系列SoC 硬件平臺 |
LCD | Liquid Crystal Display, 液晶顯示器 |
MIPI | Mobile Industry Processor Interface |
DSI | Display Serial Interface,顯示串行接口 |
I8080 | Intel 8080LCD 接口 |
RGB | 這里指一種LCD 接口,該接口發送不經過任何編碼的RGB 分量 |
LVDS | Low-Voltage Differential Signaling 一種LCD 接口,低壓和差分傳輸是其特點 |
3 IC 規格
LCD 接口相關規格:
支持雙顯,異顯。也就是顯示內容可以不一樣,顯示分辨率可以不一樣,屏接口也可以不一樣。
支持MIPI-DSI 接口, 數量一個。最大支持1920x1200@60 分辨率,滿足寬高不要超過2048,像素時鐘不超過180MHz 都支持。
支持RGB 接口,數量2 個。其中主顯支持并行RGB666,副顯并行支持RGB888, 并行RGB 接口最大支持1920x1200@60 分辨率,滿足寬高不要超過2048,像
素時鐘不超過180MHz 都支持。或者兩個串行RGB 接口,串行RGB 的最高分辨率最大不超過800*480@60
支持兩個dual-link LVDS 接口, 最大支持1920x1200@60 分辨率,滿足寬高不要超過2048,像素時鐘不超過180MHz 都支持。或者4 個single-link LVDS 接
口,分辨率最高支持1366*768@60。
兩個I8080 接口。分辨率最高支持800*480@60。
LVDS 接口支持信號同顯。每兩個single link LVDS 接口必須連接到完全一樣的LVDS 接口的屏上,將完全一樣的數據發送到這兩個屏上,做到信號一樣。所以
理論上,T509 能做到4顯,其中前2 個和后2 個分辨率可以不一樣,2 個之間的分辨率必須一樣,且必須連接一樣的LCD 屏。
說明
在多顯的場景下,以上接口可以自由搭配,除了MIPI-DSI 必須用在主顯上。
技巧
一個dual link LVDS 接口共20 條線,它可以拆分成兩個single link 的LVDS 接口,假設為lvds0 和lvds1,選擇一個single link 的時候做顯示的時候,必須選擇lvds0。
4 模塊介紹
4.1 添加屏驅動步驟
對于linux4.9 及以下版本總共需要修改三處地方(即下列前三項),對于linux5.4 則需要修改四處地方,具體可參考屏驅動源碼位置。
? linux 源碼倉庫。
? uboot 源碼倉庫。在uboot 中也有顯示和屏驅動,目的是顯示logo。
? 板級dts 配置倉庫。目的是通過board.dts 來配置一些通用的LCD 配置參數。對于linux4.9,該配置同時對內核及uboot 生效,對于linux-5.4,請參照下條。
? 對于linux5.4,還需額外配置uboot 專用板級dts 配置倉庫。
確保全志顯示框架的內核配置有使能,查看menuconfig 配置說明。
前期準備以下資料和信息:
? 屏手冊。主要是描述屏基本信息和電氣特性等,向屏廠索要。
? Driver IC 手冊。主要是描述屏IC 的詳細信息。這里主要是對各個命令進行詳解,對我們進行初始化定制有用,向屏廠索要。
? 屏時序信息。請向屏廠索要。請看屏時序參數說明以了解更多信息。
? 屏初始化代碼。,請向屏廠索要。一般情況下DSI 和I8080 屏等都需要初始化命令對屏進行初始化。
? 萬用表。調屏避免不了測量相關電壓。
動手添加屏驅動之前,先了解屏驅動,請看屏驅動分解。
通過第3 步的資料,定位該屏的類型,然后選擇一個已有同樣類型的屏驅動作為模板進行屏驅動添加或者直接在上面修改。
修改屏驅動目錄下的panel.c和panel.h。在全局結構體變量panel_array中新增剛才添加strcut_lcd_panel的變量指針。panel.h中新增strcut lcd_panel的聲
明。
修改Makefile。在lcd 屏驅動目錄的上一級的Makefile 文件中的disp-objs中新增剛才添加屏驅動.o。
修改board.dts 中的lcd0。可以看RGB 接口,MIPI-DSI 接口,I8080 接口和LVDS 接口,里面有介紹各種接口典型配置。硬件參數說明,這一章有所有lcd0 節
點下可配置屬性詳細解釋。
編譯uboot,kernel,打包燒寫。注意不同SDK,編譯方式有所不同,部分SDK 默認不編譯uboot。
調試。通過調試方法我們可以初步定位問題,還有FAQ,對調屏也有幫助。
4.2 屏驅動說明
4.2.1 屏驅動源碼位置
linux 3.4 版本內核:
linux3-4/drivers/video/sunxi/disp2/disp/lcd/
linux 3.10 版本內核:
linux3-10/drivers/video/sunxi/disp2/disp/lcd/
linux 4.9 版本及其以上內核:
linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/lcd/
uboot-2014:
brandy/u-boot-2014.07/drivers/video/sunxi/disp2/disp/lcd
uboot-2018:
brandy/brandy-2.0/u-boot-2018/drivers/video/sunxi/disp2/disp/lcd
板級配置,其中“芯片型號” 比如R818,和“板子名稱” 比如demo,請根據實際替換。
device/config/chips/芯片型號/configs/板子名稱/board.dts
針對linux5.4 時使用的uboot 板級配置:
device/config/chips/芯片型號/configs/板子名稱/uboot-board.dts
針對linux5.4 時使用的kernel 板級配置:
device/config/chips/芯片型號/configs/板子名稱/linux-5.4/board.dts
4.2.2 menuconfig 配置說明
LCD 相關代碼包含在disp 驅動模塊中,進入內核根目錄,執行make ARCH=arm menuconfig或者make ARCH=arm64 menuconfig(64bit 平臺) 進入配置主界
面。并按以下步驟操作:
DE1.0 對應平臺:R6(linux-3.10)、R16(linux-3.4)。
DE2.0 對應平臺:除R6 和R16 之外的。
?
圖4-1: DE1.0 menuconfig 配置圖
?
?
圖4-2: DE2.0 menuconfig 配置圖
?
以R40 為例,具體配置目錄為:Device Drivers->Graphics support->Support for frame buffer devices->Video Support for sunxi -> DISP Driver Support(sunxi-disp2)。
4.2.3 屏驅動分解
在屏驅動源碼位置中,主要分為四類文件
panel.c和panel.h,當用戶添加新屏驅動時,是需要修改這兩個文件的,需要將屏結構體變量添加到全局結構體變量panel_array中。
lcd_source.c和lcd_source.h,這兩個文件實現的是給屏驅動使用的函數接口,比如電源開關,gpio,dsi 讀寫接口等,用戶不需要修改只需要用。
屏驅動。除了上面提到的源文件外,其它的一般一個c 文件和一個h 文件就代表一個屏驅動。
在屏驅動源碼位置的上一級,有用戶需要修改的Makefile 文件。
我們可以打開drivers/video/fbdev/sunxi/disp2/disp/lcd/default_panel.c作為屏驅動的例子,在該文件的最后
struct __lcd_panel default_panel = {
/* panel driver name, must mach the lcd_drv_name in board.dts */
.name = "default_lcd",
.func = {
.cfg_panel_info = LCD_cfg_panel_info,
.cfg_open_flow = LCD_open_flow,
.cfg_close_flow = LCD_close_flow,
}
,
};
該全局變量default_panel的成員name與lcd_driver_name必須一致,這個關系到驅動能否找到指定的文件。
接下來是func成員的初始化,這里最主要實現三個回調函數。LCD_cfg_panel_info,LCD_open_flow和LCD_close_flow。
開關屏流程即屏上下電流程,屏手冊或者driver IC 手冊中里面的Power on Sequence 和Power off Sequence。
開關屏的操作流程如下圖所示。
其中,LCD_open_flow 和LCD_close_flow 稱為開關屏流程函數, 方框中的函數, 如LCD_power_on,稱為開關屏步驟函數。
不需要進行初始化操作的LCD 屏,比如lvds 屏,RGB 屏等,LCD_panel_init 及LCD_panel_exit這函數可以為空。
?
圖4-3: LCD 開關屏流程
?
函數:LCD_open_flow
功能:LCD_open_flow 函數只會系統初始化的時候調用一次,執行每個LCD_OPEN_FUNC即是把對應的開屏步驟函數進行注冊,先注冊先執行,但并沒有立刻執
行該開屏步驟函數。
原型:
static s32 LCD_open_flow(u32 sel)
函數常用內容為:
static __s32 LCD_open_flow(__u32 sel)
{
LCD_OPEN_FUNC(sel, LCD_power_on,10);
LCD_OPEN_FUNC(sel, LCD_panel_init, 50);
LCD_OPEN_FUNC(sel, sunxi_lcd_tcon_enable, 100);
LCD_OPEN_FUNC(sel, LCD_bl_open, 0);
return 0;
}
如上,調用四次LCD_OPEN_FUNC 注冊了四個回調函數,對應了四個開屏流程, 先注冊先執行。實際上注冊多少個函數是用戶自己的自由,只要合理即可。
LCD_power_on 即打開LCD 電源,再延遲10ms;這個步驟一般用于打開LCD 相關電源和相關管腳比如復位腳。這里一般是使用電源控制函數說明和管腳控制
函數說明進行操作。
LCD_panel_init 即初始化屏,再延遲50ms;不需要初始化的屏,可省掉此步驟,這個函數一般用于發送初始化命令給屏進行屏初始化。如果是DSI 屏看DSI 相
關函數說明,如果是I8080 屏用I8080 接口函數說明,如果是其它情況比如i2c 或者spi 可以看使用iic/spi 串行接口初始化,也可以用GPIO 來進行模擬。
sunxi_lcd_tcon_enable 打開TCON,再延遲100ms;這一步是固定的,表示開始發送圖像信號。
LCD_bl_open 打開背光,再延遲0ms。前面三步搞定之后才開背光,這樣不會看到閃爍。這里一般使用的函數請看背光控制函數說明。
如下圖,這是屏手冊中典型的上電時序圖,我們編寫屏驅動的時候,也要注意,該延時就得延時。
?
圖4-4: power on
?
函數:LCD_OPEN_FUNC
功能:注冊開屏步驟函數到開屏流程中,記住這里是注冊不是執行!
原型:
void LCD_OPEN_FUNC(__u32 sel, LCD_FUNC func, __u32 delay)
參數說明:
func 是一個函數指針,其類型是:void (*LCD_FUNC) (__u32 sel),用戶自己定義的函數必須也要用統一的形式。比如:
void user_defined_func(__u32 sel)
{
//do something
}
delay 是執行該步驟后,再延遲的時間,時間單位是毫秒。
LCD_OPEN_FUNC 的第二個參數是前后兩個步驟的延時長度,單位ms,注意這里的數值請按照屏手冊規定去填,亂填可能導致屏初始化異常或者開關屏時間過
長,影響用戶體驗。
與LCD_open_flow 對應的是LCD_close_flow 是,用于注冊關屏函數,使用LCD_CLOSE_FUNC進行函數注冊,先注冊先執行,這里只是注冊回調函數不是立刻執
行。
static s32 LCD_close_flow(u32 sel)
{
/* close lcd backlight, and delay 0ms */
LCD_CLOSE_FUNC(sel, LCD_bl_close, 0);
/* close lcd controller, and delay 0ms */
LCD_CLOSE_FUNC(sel, sunxi_lcd_tcon_disable, 50);
/* open lcd power, than delay 200ms */
LCD_CLOSE_FUNC(sel, LCD_panel_exit, 100);
/* close lcd power, and delay 500ms */
LCD_CLOSE_FUNC(sel, LCD_power_off, 0);
return 0;
}
先關閉背光,這樣整個關屏過程,用戶不會看到閃爍的過程。
關閉TCON,也就是停止發送數據,這是必要的。再延遲50ms。
執行關屏代碼,再延遲200ms(不需要初始化的屏,可省掉此步驟)。
最后關閉電源,再延遲0ms。
如下圖是典型關屏時序圖。
?
圖4-5: power off
?
函數:LCD_cfg_panel_info
功能:配置的TCON 擴展參數,比如gamma 功能和顏色映射功能。
原型:
static void LCD_cfg_panel_info(__panel_extend_para_t * info)
TCON 的擴展參數只能在屏文件中配置,參數的定義見顯示效果相關參數。
需要gamma 校正,或色彩映射,在board.dts 中將相應模塊的enable 參數置1,lcd_gamma_en,lcd_cmap_en,并且填充3 個系數表,lcd_gamma_tbl,
lcd_cmap_tbl,如下所示代碼部分。注意的是:gamma,模板提供了18 段拐點值,然后再插值出所有的值(255 個)。如果覺得還不細,可以往相應表格里添加
子項。cmap_tbl 的大小是固定了,不能減小或增加表的大小。
最終生成的gamma 表項是由rgb 三個gamma 值組成的,各占8bit,目前提供的模板中,三個gamma 值是相同的。
static void LCD_cfg_panel_info(struct panel_extend_para *info)
{
u32 i = 0, j = 0;
u32 items;
u8 lcd_gamma_tbl[][2] = {
/* {input value, corrected value} */
{0, 0},
{15, 15},
{30, 30},
{45, 45},
{60, 60},
{75, 75},
{90, 90},
{105, 105},
{120, 120},
{135, 135},
{150, 150},
{165, 165},
{180, 180},
{195, 195},
{210, 210},
{225, 225},
{240, 240},
{255, 255},
};
u32 lcd_cmap_tbl[2][3][4] = {
{
{LCD_CMAP_G0, LCD_CMAP_B1, LCD_CMAP_G2, LCD_CMAP_B3},
{LCD_CMAP_B0, LCD_CMAP_R1, LCD_CMAP_B2, LCD_CMAP_R3},
{LCD_CMAP_R0, LCD_CMAP_G1, LCD_CMAP_R2, LCD_CMAP_G3},
},
{
{LCD_CMAP_B3, LCD_CMAP_G2, LCD_CMAP_B1, LCD_CMAP_G0},
{LCD_CMAP_R3, LCD_CMAP_B2, LCD_CMAP_R1, LCD_CMAP_B0},
{LCD_CMAP_G3, LCD_CMAP_R2, LCD_CMAP_G1, LCD_CMAP_R0},
},
};
items = sizeof(lcd_gamma_tbl) / 2;
for (i = 0; i < items - 1; i++) {
u32 num = lcd_gamma_tbl[i + 1][0] - lcd_gamma_tbl[i][0];
for (j = 0; j < num; j++) {
u32 value = 0;
value =
lcd_gamma_tbl[i][1] +
((lcd_gamma_tbl[i + 1][1] -
lcd_gamma_tbl[i][1]) * j) / num;
info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] =
(value << 16) + (value << 8) + value;
}
}
info->lcd_gamma_tbl[255] =
(lcd_gamma_tbl[items - 1][1] << 16) +
(lcd_gamma_tbl[items - 1][1] << 8) + lcd_gamma_tbl[items - 1][1];
memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl));
}
4.2.4 延時函數說明
函數:sunxi_lcd_delay_ms / sunxi_lcd_delay_us
功能:延時函數,分別是毫秒級別/微秒級別的延時。
原型:s32 sunxi_lcd_delay_ms(u32 ms) / s32 sunxi_lcd_delay_us(u32 us)
4.2.5 圖像數據使能函數說明
函數:sunxi_lcd_tcon_enable / sunxi_lcd_tcon_disable
功能:打開LCD 控制器,開始刷新LCD 顯示。關閉LCD 控制器,停止刷新數據。
原型:void sunxi_lcd_tcon_enable(u32 screen_id)
void sunxi_lcd_tcon_disable(u32 screen_id)
4.2.6 背光控制函數說明
函數:sunxi_lcd_backlight_enable / sunxi_lcd_backlight_disable
功能:打開/關閉背光,操作的是board.dts 中lcd_bl 配置的gpio。見lcd_bl_en。
原型:void sunxi_lcd_backlight_enable(u32 screen_id)
void sunxi_lcd_backlight_disable(u32 screen_id)
函數:sunxi_lcd_pwm_enable / sunxi_lcd_pwm_disable
功能:打開/關閉pwm 控制器,打開時pwm 將往外輸出pwm 波形。對應的是lcd_pwm_ch所對應的那一路pwm。
原型:s32 sunxi_lcd_pwm_enable(u32 screen_id)
s32 sunxi_lcd_pwm_disable(u32 screen_id)
4.2.7 電源控制函數說明
函數:sunxi_lcd_power_enable / sunxi_lcd_power_disable
功能:打開/關閉Lcd 電源,操作的是board.dts 中的lcd_power/lcd_power1/lcd_power2(pwr_id 標識電源索引)。
原型:void sunxi_lcd_power_enable(u32 screen_id, u32 pwr_id)
void sunxi_lcd_power_disable(u32 screen_id, u32 pwr_id)
pwr_id = 0:對應于board.dts 中的lcd_power。
pwr_id = 1:對應于board.dts 中的lcd_power1。
pwr_id = 2:對應于board.dts 中的lcd_power2。
pwr_id = 3:對應于board.dts 中的lcd_power3。
函數:sunxi_lcd_pin_cfg
功能:配置lcd 的io。
原型:s32 sunxi_lcd_pin_cfg(u32 screen_id, u32 bon)
說明:配置lcd 的data/clk 等pin,對應board.dts 中的lcdd0-lcdd23/lcddclk/lcdde/lcdhsync/lcdvsync。
由于dsi 是專用pin, 所以dsi 接口屏不需要在board.dts 中配置這組pin,但同樣會在此函數接口中打開與關閉對應的pin。
Bon: 1: 為開,0:為配置成disable 狀態。
4.2.8 DSI 相關函數說明
MIPI DSI 屏,大部分需要初始化,使用的是DSI-D0 通道的LP 模式進行初始化。提供的接口函數說明如下:
函數:sunxi_lcd_dsi_clk_enable / sunxi_lcd_dsi_clk_disble
功能:僅限dsi 接口屏使用,使能/關閉dsi 輸出的高速時鐘clk 信號,必須在初始化的時候調用。
原型:s32 sunxi_lcd_dsi_clk_enable(u32 scree_id)
s32 sunxi_lcd_dsi_clk_disable(u32 scree_id)
函數:sunxi_lcd_dsi_dcs_wr
功能:對屏的dcs 寫操作。
原型:s32 sunxi_lcd_dsi_dcs_wr(u32 sel,u8 cmd,u8* para_p,__u32 para_num)
參數說明:
? cmd:dcs 寫命令內容。
? para_p:dcs 寫命令的參數起始地址。
? para_num:dcs 寫命令的參數個數,單位為byte。
函數:sunxi_lcd_dsi_dcs_wr_2para
功能:對屏的dcs 寫操作,該命令帶有兩個參數。
原型:s32 sunxi_lcd_dsi_dcs_wr_2para(u32 sel,u8 cmd,u8 para1,__u8 para2)
參數說明:
? cmd:dcs 寫命令內容。
? para1:dcs 寫命令的第一個參數內容。
? para2:dcs 寫命令的第二個參數內容。
sunxi_dsi_dcs_wr_0para,sunxi_dsi_dcs_wr_1para,sunxi_dsi_dcs_wr_3para,sunxi_dsi_dcs_wr_4para,
sunxi_dsi_dcs_wr_5para定義與dsi_dcs_wr_2para類似,差別就是參數數量。
函數:sunxi_lcd_dsi_dcs_read
功能:dsi 讀操作。
原型:s32 sunxi_lcd_dsi_dcs_read(u32 sel, u8 cmd, u8 result, u32 num_p)
參數說明:
? sel, 顯示id。
? cmd, 要讀取的寄存器。
? result,用于存放讀取接口的數組,用戶必須自行保證其有足夠空間保存讀取的接口。
? num_p,指針用于存放讀取字節數,用戶必須保證其非空指針。
4.2.9 I8080 接口函數說明
顯示驅動提供5 個接口函數可供使用。如下:
函數:sunxi_lcd_cpu_write
功能:設定CPU 屏的指定寄存器為指定的值。
原型:void sunxi_lcd_cpu_write(u32 sel, u32 index, __u32 data)
函數內容為:
Void sunxi_lcd_cpu_write(__u32 sel, __u32 index, __u32 data) { sunxi_lcd_cpu_write_index(sel, index); sunxi_lcd_cpu_wirte_data(sel, data); }
實現了8080 總線上的兩個寫操作。
sunxi_lcd_cpu_write_index 實現第一個寫操作,這時PIN 腳RS(A1)為低電平,總線數據上的數據內容為參數index 的值。
Sunxi_lcd_cpu_wirte_data 實現第二個寫操作,這時PIN 腳RS(A1)為高電平,總線數據上的數據內容為參數data 的值。
函數:sunxi_lcd_cpu_write_index
功能:設定CPU 屏為指定寄存器。
原型:
void sunxi_lcd_cpu_write_index(__u32 sel,__u32 index)
具體說明見sunxi_lcd_cpu_write。
函數:sunxi_lcd_cpu_write_data
功能:設定CPU 屏寄存器的值為指定的值。
原型:
void Sunxi_lcd_cpu_write_data(__u32 sel, __u32 data);
函數: tcon0_cpu_rd_24b_data
功能:讀操作。
原型:
s32 tcon0_cpu_rd_24b_data(u32 sel, u32 index, u32 *data, u32 size)
參數說明:
? sel:顯示id。
? index: 要讀取的寄存器。
? data:用于存放讀取接口的數組指針,用戶必須保證其有足夠空間存放數據。
? size:要讀取的字節數。
4.2.10 管腳控制函數說明
函數:sunxi_lcd_gpio_set_value
功能:LCD_GPIO PIN 腳上輸出高電平或低電平。
原型:s32 sunxi_lcd_gpio_set_value(u32 screen_id, u32 io_index, u32 value)
參數說明:
? io_index = 0:對應于board.dts 中的lcd_gpio_0。
? io_index = 1:對應于board.dts 中的lcd_gpio_1。
? io_index = 2:對應于board.dts 中的lcd_gpio_2。
? io_index = 3:對應于board.dts 中的lcd_gpio_3。
? value = 0:對應IO 輸出低電平。
? Value = 1:對應IO 輸出高電平。
只用于該GPIO 定義為輸出的情形。
函數:sunxi_lcd_gpio_set_direction
功能:設置LCD_GPIO PIN 腳為輸入或輸出模式。
原型:
s32 sunxi_lcd_gpio_set_direction(u32 screen_id, u32 io_index, u32 direction);
參數說明:
? io_index = 0:對應于board.dts 中的lcd_gpio_0。
? io_index = 1:對應于board.dts 中的lcd_gpio_1。
? io_index = 2:對應于board.dts 中的lcd_gpio_2。
? io_index = 3:對應于board.dts 中的lcd_gpio_3。
? direction = 0:對應IO 設置為輸入。
? direction = 1:對應IO 設置為輸出。
一部分屏需要進行初始化操作,在開屏步驟函數中,對應于LCD_panel_init 函數,提供了幾種方式對屏的初始化。
對于DSI 屏,是通過DSI-D0 通道進行初始化。對于CPU 屏,是通過8080 總線的方式,使用的是LCDIO(PD,PH)進行初始化。這種初始化方式,其總線的引腳位
置定義與CPU 屏一致。
以下這些接口在屏驅動分解中提到路徑的lcd_source.c 和lcd_source.h 中定義和實現。
4.2.11 使用iic/spi 串行接口初始化
需要在屏驅動中注冊iic/spi 設備對串行接口的訪問。
使用硬件spi 對屏或者轉接IC 進行初始化,如下代碼片段。
首先調用spi_init 函數對spi 硬件進行初始化,spi_init 函數可以分為幾個步驟,第一獲取master;根據實際的硬件連接,選擇spi(代碼中選擇了spi1),如果這一
步返回錯誤說spi 沒有配置好,找spi 驅動負責人。第二步設置spi device,這里包括最大速度,spi 傳輸模式,以及每個字包含的比特數。最后調用spi_setup 完成
master 和device 的關聯。
comm_out 是一個spi 傳輸的例子,核心就是spi_sync_transfer 函數。
static int spi_init(void) { int ret = -1; struct spi_master *master; master = spi_busnum_to_master(1); if (!master) { lcd_fb_wrn("fail to get mastern"); goto OUT } spi_device = spi_alloc_device(master); if (!spi_device) { lcd_fb_wrn("fail to get spi devicen"); goto OUT; } spi_device->bits_per_word = 8; spi_device->max_speed_hz = 60000000; /*50MHz*/ spi_device->mode = SPI_MODE_0; ret = spi_setup(spi_device); if (ret) { lcd_fb_wrn("Faile to setup spin"); goto FREE; } lcd_fb_inf("Init spi1:bits_per_word:%d max_speed_hz:%d mode:%dn", spi_device->bits_per_word, spi_device->max_speed_hz, spi_device->mode); ret = 0; goto OUT; FREE: spi_master_put(master); kfree(spi_device); spi_device = NULL; OUT: return ret; } static int comm_out(unsigned int sel, unsigned char cmd) { struct spi_transfer t; if (!spi_device) return -1; DC(sel, 0); memset(&t, 0, sizeof(struct spi_transfer)); t.tx_buf = &cmd; t.len = 1; t.bits_per_word = 8; t.speed_hz = 24000000; return spi_sync_transfer(spi_device, &t, 1); }
使用硬件i2c 對LCD& 轉接IC 進行初始化,初始化i2c 硬件的核心函數是i2c_add_driver,而你要做的是初始化好其參數struct i2c_driver。
it66121_id 包含設備名字以及i2c 總線索引(i2c0,i2c1…)。
it66121_i2c_probe 能進到這個函數,你就可以開始使用i2c 了。代碼段里面僅僅將后面需要的參數cilent 賦值給一個全局指針變量。
it66121_match,這是dts 的match table,由于你是給disp2 加驅動,所以這里的match table 就是disp2 的match table,這個table 關系到能否使用i2c,注意不
要填錯。 tv_i2c_detect 函數,這里是非常關鍵的,這個函數早于probe 函數被調用,只有成功被調用后才能開始使用i2c,其中strlcpy 的調用意味著成功。
normal_i2c 是從設備地址列表,填寫的LCD 或者轉接IC 的從設備地址以及i2c 索引。
以probe 函數是否被調用來決定你是否可以開始使用I2C。
用i2c_smbus_write_byte_data 或者i2c_smbus_read_byte_data 來讀寫可以滿足大部分場景。
#define IT66121_SLAVE_ADDR 0x4c #define IT66121_I2C_ID 0 static const struct i2c_device_id it66121_id[] = { { "IT66121", IT66121_I2C_ID }, { /* END OF LIST */ } }; MODULE_DEVICE_TABLE(i2c, it66121_id); static int it66121_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { this_client = client; return 0; } static const struct of_device_id it66121_match[] = { {.compatible = "allwinner,sun8iw10p1-disp",}, {.compatible = "allwinner,sun50i-disp",}, {.compatible = "allwinner,sunxi-disp",}, {}, }; static int tv_i2c_detect(struct i2c_client *client, struct i2c_board_info *info) { const char *type_name = "IT66121"; if (IT66121_I2C_ID == client->adapter->nr) { strlcpy(info->type, type_name, 20); } else pr_warn("%s:%d wrong i2c id:%d, expect id is :%dn", __func__, __LINE__, client->adapter->nr, IT66121_I2C_ID); return 0; } static unsigned short normal_i2c[] = {IT66121_SLAVE_ADDR, I2C_CLIENT_END}; static struct i2c_driver it66121_i2c_driver = { .class = I2C_CLASS_HWMON, .id_table = it66121_id, .probe = it66121_i2c_probe, .remove = it66121_i2c_remove, .driver = { .owner = THIS_MODULE, .name = "IT66121", .of_match_table = it66121_match, }, .detect = tv_i2c_detect, .address_list = normal_i2c, }; static void LCD_panel_init(u32 sel) { int ret = -1; ret = i2c_add_driver(&it66121_i2c_driver); if (ret) { pr_warn("Add it66121_i2c_driver fail!n"); return; } //start init chip with i2c } void it6612_twi_write_byte(it6612_reg_set* reg) { u8 rdata = 0; u8 tmp = 0; rdata = i2c_smbus_read_byte_data(this_client, reg->offset); tmp = (rdata & (~reg->mask))|(reg->mask?->value); i2c_smbus_write_byte_data(this_client, reg->offset, tmp); }
4.2.12 U-boot 屏驅動注意事項
U-boot 編寫屏驅動的步驟和內核是一樣的,代碼路徑文件組織方式都是一樣的,這里要講的是需要注意的事項。
1.為了加快U-boot 的顯示速度,開屏的幾個函數之間采取異步調用的方式,原理是利用timer中斷,定時調用開屏函數,所以這種情況下bootGUI 框架加載完畢并
不意味著開屏完成,而是當你見到LCD open finish的打印的時候。
建議:為了盡量利用異步調用的優點,請把需要的延時盡量在注冊回調的時候指定,比如下面延時10ms 就是利用timer 異步來進行回調的,這10ms 時間,uboot
就可以做其它事情,以達到異步調用的目的。
LCD_OPEN_FUNC(sel, LCD_power_on,10);
2.sunxi_lcd_power_enable 函數和sunxi_lcd_pin_cfg 不能在LCD_power_on之外調用,否則uboot 會異常。
嚴格講,只能在用LCD_OPEN_FUNC注冊的回調第一個函數里面調用。
4.3 RGB 接口
4.3.1 概述
下面介紹全志平臺的RGB 以及配置示例,至于lcd0 下面每個屬性的詳解細節請看硬件參數說明。
RGB 接口在全志平臺又稱HV 接口(Horizontal 同步和Vertical 同步)。
對于RGB 屏的初始化:
有些LCD 屏支持高級的功能比如gamma,像素格式的設置等,但是RGB 協議本身不支持圖像數據之外的傳輸,所以無法通過RGB 管腳進行對LCD 屏進行配置,
所以拿到一款RGB 接口屏,要么不需要初始化命令,要么這個屏會提供額外的管腳給SoC 來進行配置,比如SPI 和I2C等。
4.3.2 RGB 接口管腳
?
圖4-6: RGB 管腳
?
上面這些腳具體到SoC 哪根管腳以及第幾個功能(管腳復用功能)請參考pin mux 表格,管腳復用功能的名字一般以“LCDX_” 開頭,其中X 是數字。
其中數據腳的數量不一定是24 根。RGB 又細分幾種接口,通過設置lcd_hv_if來選擇。
?
表4-1: RGB 接口分類
?
位寬 | 時鐘周期 | 數顏色數量和格式 |
---|---|---|
24 bits | 1 cycle | 16.7M colors, RGB888 |
18 bits | 1 cycle | 262K colors, RGB666 |
16 bits | 1 cycle | 65K colors, RGB565 |
6 bits | 3 cycles | 262K colors, RGB666 |
6 bits | 3 cycles | 65K colors, RGB565 |
說明
時鐘周期數的意思:是一個像素需要用多少個時鐘周期發送完畢的意思。
當時鐘周期為1 時,我們稱這種RGB 接口為并行接口,其它的情況則是串行接口,更為普遍的原則就是只要需要多個時鐘周期才能發送完一個像素的接口都是串行
接口。
如何判斷是否支持24bit 的位寬,最簡單的方式就是在pinmux 表格中數一數數據腳的數量,如果有24 根則支持24bit,如果只有18 根則支持18bit。
硬件連接
對于并行RGB 的接口,當位寬小于24 時,硬件連接應該選擇連接每個分量中的高位而放棄低位,這樣做的原因是損失較少的顏色數量。
對于串行RGB 接口,硬件連接可參考RGB 和I8080 管腳配置示意圖中sync RGB 那幾列。
RGB 接口有兩種同步方式,根據經驗來說盡量使用第二種方式,硬件上請保證連接好DE 腳。
Hsync+Vsync
DE(Data Enable)
4.3.3 并行RGB 接口配置示例
當我們配置并行RGB 接口時,在配置里面并不需要區分是24 位,18 位和16 位,最大位寬是哪種是參考pin mux 表格,如果LCD 屏本身支持的位寬比SoC 支持的
位寬少,當然只能選擇少的一方。
因為不需要初始化,RGB 接口極少出現問題,重點關注lcd 的timing 的合理性,也就是lcd_ht,lcd_hspw,lcd_hbp,lcd_vt,lcd_vspw和lcd_vbp這個屬性的合理
性。
下面是典型并行RGB 接口board.dts 配置示例,其中用空行把配置分成幾個部分
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化,這里是default_lcd,是針對不需要初始化設置的
RGB 屏
第二部分決定下面的配置是一個并行RGB 的配置。
第三部分決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
第四部分決定了背光(pwm 和lcd_bl_en)。請看背光相關參數。
第五部分是顯示效果部分的配置,如果非24 位的RGB,那么一般情況下需要設置lcd_frm。
第六部分就是電源和管腳配置。是用RGB666 還是RGB888,需要根據實際pinmux 表來決定,如果該芯片只有18 根rgb 數據則只能rgb18。請看電源和管腳
參數。
&lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "default_lcd"; /* part 2 */ lcd_if = <0>; lcd_hv_if = <0>; /* part 3 */ lcd_width = <150>; lcd_height = <94>; lcd_x = <800>; lcd_y = <480>; lcd_dclk_freq = <33>; lcd_hbp = <46>; lcd_ht = <1055>; lcd_hspw = <0>; lcd_vbp = <23>; lcd_vt = <525>; lcd_vspw = <0>; /* part 4 */ lcd_backlight = <50>; lcd_pwm_used = <1>; lcd_pwm_ch = <8>; lcd_pwm_freq = <10000>; lcd_pwm_pol = <1>; lcd_bl_en = <&pio PD 27 1 0 3 1>; lcd_bright_curve_en = <0>; /* part 5 */ lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_gamma_en = <0>; lcd_cmap_en = <0>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; /* part 6 */ lcd_power = "vcc-lcd"; lcd_pin_power = "vcc-pd"; pinctrl-0 = <&rgb24_pins_a>; pinctrl-1 = <&rgb24_pins_b>; };
4.3.4 串行RGB 接口的典型配置
串行RGB 是相對于并行RGB 來說,而并不是說它只用一根線來發數據,只要通過多個時鐘周期才能把一個像素的數據發完,那么這樣的RGB 接口就是串行RGB。
同樣與并行RGB 接口一樣,配置中并不需要也無法體現具體是哪種串行RGB 接口,需要做的就是把硬件連接對。
下面是典型串行RGB 接口board.dts 配置示例,它只有8 根數據腳,其中用空行把配置分成幾個部分
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化。
第二分部決定下面的配置是一個串行RGB 的配置。
第三部分決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
技巧 這里需要注意的是,對于該接口,SoC 總共需要三個周期才能發完一個pixel,所以我們配置時序的時候,需要滿足lcd_dclk_freq3=lcd_htlcd_vt60,或者
lcd_dclk_freq=lcd_ht3lcd_vt60要么3 倍lcd_ht要么3倍lcd_dclk_freq。
第四部分決定了背光。就是pwm 和lcd_bl_en。請看背光相關參數
第五部分是顯示效果方面的設置。
第六部分管腳和電源的定義。請看電源和管腳參數。
說明
下面實例的lcd driver IC 是stv7789v,是需要初始化,初始化的接口協議是SPI,所以這多了幾根spi 管腳配置,驅動里面用gpio 模擬spi 協議,所以這里都是配置
gpio 功能。
&lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "st7789v"; /* part 2 */ lcd_if = <0>; lcd_hv_if = <8>; /* part 3 */ lcd_x = <240>; lcd_y = <320>; lcd_width = <108>; lcd_height = <64>; lcd_dclk_freq = <19>; lcd_hbp = <120>; ;10 + 20 + 10 + 240*3 = 760 real set 1000 lcd_ht = <850>; lcd_hspw = <2>; lcd_vbp = <13>; lcd_vt = <373>; lcd_vspw = <2>; /* part 4 */ lcd_backlight = <50>; lcd_pwm_used = <1>; lcd_pwm_ch = <8>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_bl_en = <&pio PB 1 1 0 3 1>; lcd_bright_curve_en = <1>; /* part 5 */ lcd_frm = <1>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; lcd_hv_srgb_seq = <0>; lcd_io_phase = <0x0000>; lcd_gamma_en = <0>; lcd_cmap_en = <0>; lcd_rb_swap = <0>; /* part 6 */ lcd_power = "vcc-lcd"; lcd_pin_power = "vcc-pd"; /*reset */ lcd_gpio_0 = <&pio PD 9 1 0 3 1>; /* cs */ lcd_gpio_1 = <&pio PD 10 1 0 3 0>; /*sda */ lcd_gpio_2 = <&pio PD 13 1 0 3 0>; /*sck */ lcd_gpio_3 = <&pio PD 12 1 0 3 0>; pinctrl-0 = <&rgb8_pins_a>; pinctrl-1 = <&rgb8_pins_b>; };
4.4 MIPI-DSI 接口
4.4.1 概述
MIPI-DSI,即Mobile Industry Processor Interface Display Serial Interface,移動通信行業處理器接口顯示串行接口。
對于用戶來說,需要了解:
Command mode,類似MPU 接口,需要IC 內部有GRAM 來緩沖。
Video mode。類似RGB 接口,沒有GRAM,需要不停往panel 刷數據。其中video mode又分為三個子mode。
? Non-burst mode with sync pulses
? Non Burst mode with sync Events
? Burst mode。簡單理解就是有效數據比率更高,傳輸效率更高。
lane 的意思是指一對差分管腳。
4.4.2 MIPI-DSI 的管腳
MIPI-DSI 的管腳是在大部分IC 中是專用,在board.dtsi 里面不需要配置,只要硬件上連接好就行。
但是有一部分IC 的DSI 管腳不是專用的,與其它功能的腳復用,這個時候就需要配置好pinctrl-0和pinctrl-1。
mipi-dsi 的管腳是差分的,分為兩種管腳,一種是時鐘管腳,另外一種是數據管腳,數據管腳的數量是可變的,數量的單位是lane,每一條lane 實際包含兩條線。
一般來說LCD 屏說明書里面的說的lane 的數量是指數據管腳的數量不包括時鐘管腳。比如說某4 lane MIPI-DSI 屏就總共有(4+1)*2根腳。
4.4.3 MIPI-DSI 的電源
一般都有一路電源供給MIPI-DSI 這個模塊,你可以理解為管腳電,也可以理解成模塊電,不同IC 這路電的電壓要求可能不同,一旦確定IC 型號之后,這路電的電
壓就不變,如果擅自改變此路電的電壓可能導致模塊異常。
?
圖4-7: pinmux
?
4.4.4 判斷是否支持某款MIPI-DSI 屏
1.分辨率限制。有lane 的速度限制,我們可以得到最大分辨率的限制,計算公式如下,只要lane_speed 不超過上面IC 規格規定的速度,那么理論上是支持的,
請查看IC 規格。
lane_speed=lcd_vt * lcd_ht * fps * bit_per_pixel / lane_num / 1e9
? 單位:Gbps。
? fps: 期望刷新率,通過屏手冊可知道,一般是60。請看lcd_dclk_freq。
? bit_per_pixel: 每個像素包含的比特數量,一般是24 或者18,通過lcd_dsi_format來設置。
? lane_num:lane 數量,通過lcd_dsi_lane來設置。
? 1e9:1000000000 的科學計數寫法。
選擇分辨率的同時需要考慮系統帶寬,DE 能力,所以即使接口方面支持這個分辨率,對于整個系統來說不一定支持,比如說硬件為了節省成本選擇了一款速
度很慢的DDR 內存然后同時又想選擇高分辨率的屏幕,很明顯這是不現實的。
lane 數量限制。絕大部分全志科技IC 最大支持4 lane 的MIPI-DSI,如果你看到該款屏超過4 lane 就肯定不支持了。少數IC 最大支持8 lane,應該選擇該款
IC。
MIPI-DSI 標準不兼容。請查看IC 規格。
4.4.5 計算MIPI-DSI 時鐘lane 頻率
使用示波器測量MIPI-DSI 的時鐘信號,確定其頻率是否滿足屏的需求。
首先,我們由給定的像素時鐘和lane 數量,可以計算出理論CLK 信號的頻率,如下公式:
Freq_dsi_clk = (Dclk * colordepth * 3 / lane ) / 2
Freq_dsi_clk:我們要測量的dsi 時鐘腳的頻率。單位MHz。
Dclk:像素時鐘。由lcd_htlcd_vtfps/1e6公式算出來。
Colordepth:顏色深度,一般是8 或者6。
乘以3 表示RGB 分量3 個。
Lane:dsi 的lane 數量。
除以2:是因為dsi 時鐘是雙沿采樣。
4.4.6 MIPI-DSI Video mode 屏配置示例
絕大多數MIPI-DSI 屏的配置都是用video mode。
下面是典型MIPI-DSI video mode 的board.dts 配置示例,其中用空行把配置分成幾個部分
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化。
第二部分,決定該配置是dsi 接口,而且dsi 接口使用的是video mode。
第三部分,決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
第四部分,背光相關的設置。請看背光相關參數。
第五部分,dsi 接口的詳細設置。
第六部分,顯示效果相關的設置。
第七部分,管腳和電源設置。請看電源和管腳參數。
&lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "k101im2qa04"; /* part 2 */ lcd_if = <4>; lcd_dsi_if = <0>; /* part 3 */ lcd_x = <800>; lcd_y = <1280>; lcd_width = <135>; lcd_height = <216>; lcd_dclk_freq = <68>; lcd_hbp = <36>; lcd_ht = <854>; lcd_hspw = <18>; lcd_vbp = <12>; lcd_vt = <1320>; lcd_vspw = <4>; /* part 4 */ lcd_backlight = <50>; lcd_pwm_used = <1>; lcd_pwm_ch = <0>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_bl_en = <&pio PB 8 1 0 3 1>; lcd_bright_curve_en = <0>; /* part 5 */ lcd_dsi_lane = <4>; lcd_dsi_format = <0>; lcd_dsi_te = <0>; /* part 6 */ lcd_frm = <0>; lcd_gamma_en = <0>; lcd_cmap_en = <0>; /* part 7 */ lcd_pin_power = "dcdc1"; lcd_pin_power1 = "eldo3"; lcd_power = "dc1sw"; lcd_gpio_0 = <&pio PD 22 1 0 3 1>; pinctrl-0 = <&dsi4lane_pins_a>; pinctrl-1 = <&dsi4lane_pins_b>; };
4.4.7 MIPI-DSI 超高分辨率屏配置示例
根據分辨率的高低通常分為幾種模式來配置。1080p 分辨率及其以下:只需要設置lcd_dsi_if 來控制就行。Command mode 一般是低分辨率屏,而video mode
和burst mode 則是用于高分辨率的。如果分辨率達到2k,則需要額外的設置。
分辨率達到2k 以上的屏,實際上需要多達8 條數據lane 才能正常顯示,其中四條lane 發送一副圖像中的奇像素,另外一副圖像發送偶像素。
說明
注意只有部分IC 支持超高分辨率,具體查看芯片規格中的MIPI-DSI 部分
下面是MIPI-DSI 高分辨超高分辨率(大于2k)board.dts 配置示例,其中用空行把配置分成幾個部分
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化。
第二部分,決定該配置是dsi 接口,而且dsi 接口使用的是video mode。
第三部分,決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
第四部分,背光相關的設置,請看背光相關參數。
第五部分,dsi 接口的詳細設置。
說明 lcd_dsi_lane 依舊設置成4 條lane 的原因,是因為這個是設置一個dsi 的lane 數量,這個屏要用兩個dsi。加起來就是8 條lane。
此時lcd_tcon_mode, lcd_dsi_port_num 和lcd_tcon_en_odd_even_div 三個選項需要特別設置,點擊查看具體含義,如果是1080p 及其以下分辨率的屏(只用
4lane 或者以下的),那么這三個配置默認0 即可。
第六部分,顯示效果部分的設置。
第七部分,是管腳和電源的配置。請根據電路圖來配置。請看電源和管腳參數。
&lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "lq101r1sx03"; /* part 2 */ lcd_if = <4>; lcd_dsi_if = <0>; /* part 3 */ lcd_x = <2560>; lcd_y = <1600>; lcd_width = <216>; lcd_height = <135>; lcd_dclk_freq = <268>; lcd_hbp = <80>; lcd_ht = <2720>; lcd_hspw = <32>; lcd_vbp = <37>; lcd_vt = <1646>; lcd_vspw = <6>; /* part 4 */ lcd_backlight = <50>; lcd_pwm_used = <1>; lcd_pwm_ch = <0>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_bl_en = <&pio PH 10 1 0 3 1>; /* part 5 */ lcd_dsi_lane = <4>; lcd_dsi_format = <0>; lcd_dsi_te = <0>; lcd_dsi_port_num = <1>; lcd_tcon_mode = <4>; lcd_tcon_en_odd_even_div = <1>; /* part 6 */ lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; /* part 7 */ lcd_power = "vcc18-lcd"; lcd_power1 = "vcc33-lcd"; lcd_pin_power = "vcc-pd"; lcd_gpio_0 = <&pio PH 11 1 0 3 1>; lcd_gpio_1 = <&pio PH 12 1 0 3 1>; };
4.4.8 MIPI-DSI Command mode 屏配置示例
Command mode 下的DSI 屏類似與I8080 接口,屏內部帶RAM 用于緩沖和圖像處理,這種情況一般都需要用屏的te 腳來觸發vsync 中斷,所以與其它類型的DSI
屏不同的是,這里需要設置lcd_vsync 腳,屏的te 腳就連到lcd_vsync 上,并且lcd_dsi_te 設置成1。
te 腳的設置非常關鍵,一般來說如果屏有te 腳,則必須連上,否則在顯示動態畫面的時候會畫面會撕裂,而且軟件無法解決,直接造成最終硬件無法量產的結
果。
這里只列舉出與MIPI-DSI video mode 不同的關鍵之處,其它參考上一小節。
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化。
第二部分,決定該配置是dsi 接口,而且lcd_dsi_if設置成1 表明command mode。
第三部分,決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
第四部分,背光相關的設置。請看背光相關參數。
第五部分,dsi 接口的詳細設置。lcd_dsi_te,這里設置為1 表示使能te 觸發。
第六部分,顯示效果相關的設置。
第七部分,管腳和電源設置。lcd_vsync,這里是te 腳,硬件上需要將這根腳連接到屏的te腳,軟件上需要將其設置為vsync 功能。請看電源和管腳參數。
&lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "h245qbn02"; /* part 2 */ lcd_if = <4>; lcd_dsi_if = <1>; /* part 3 */ lcd_x = <240>; lcd_y = <432>; lcd_width = <52>; lcd_height = <52>; lcd_dclk_freq = <18>; lcd_hbp = <96>; lcd_ht = <480>; lcd_hspw = <2>; lcd_vbp = <21>; lcd_vt = <514>; lcd_vspw = <2>; /* part 4 */ lcd_backlight = <100>; lcd_pwm_used = <1>; lcd_pwm_ch = <0>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_bright_curve_en = <0>; lcd_bl_en = <&pio PB 3 1 0 3 1>; /* part 5 */ lcd_dsi_lane = <1>; lcd_dsi_format = <0>; lcd_dsi_te = <1>; lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_gamma_en = <0>; lcd_cmap_en = <0>; /* part 7 */ lcd_power = "axp233_dc1sw" lcd_power1 = "axp233_eldo1" lcd_gpio_0 = <&pio PB 2 1 0 3 0>; lcd_vsync = <&pio PD 21 2 0 3 0>; };
4.4.9 MIPI-DSI VR 雙屏配置示例
實際場景是兩個物理屏,每個屏是1080p,每個屏都是4 條lane,要求的是兩個屏各自顯示一幀圖像的左右一半,由于寬高比和橫豎屏以及DE 處理能力的因素,
一個DE+ 一個tcon+ 兩個DSI 已經無法滿足,必須用兩個tcon 各自驅動一個dsi,但是兩路顯示必須要同步,這就需要用到兩個tcon 的同步模式。
LCD0 標記為slave tcon,它由master tcon 來驅動(設置lcd_tcon_mode)。
LCD1 標記為master tcon,并且負責兩個屏的所有電源,背光,管腳的開關。
把管腳,電源等都放到LCD1 開,LCD0 先開,對應模塊寄存器都初始化,但是電源不開,然后開LCD1,LCD1 使能就會觸發LCD0 一起發數據。這樣做到同時
亮滅。
說明
注意:僅有極少IC 支持該模式
&lcd0 { lcd_used = <1>; lcd_driver_name = "lpm025m475a"; ;lcd_bl_0_percent = <0>; ;lcd_bl_40_percent = <23>; ;lcd_bl_100_percent = <100>; lcd_backlight = <50>; lcd_if = <4>; lcd_x = <1080>; lcd_y = <1920>; lcd_width = <31>; lcd_height = <56>; lcd_dclk_freq = <141>; lcd_pwm_used = <0>; lcd_pwm_ch = <0>; lcd_pwm_freq = <20000>; lcd_pwm_pol = <0>; lcd_pwm_max_limit = <255>; lcd_hbp = <100>; lcd_ht = <1212>; lcd_hspw = <5>; lcd_vbp = <8>; lcd_vt = <1936>; lcd_vspw = <2>; lcd_dsi_if = <0>; lcd_dsi_lane = <4>; lcd_dsi_format = <0>; lcd_dsi_te = <0>; lcd_dsi_eotp = <0>; lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; lcd_dsi_port_num = <0>; lcd_tcon_mode = <3>; lcd_slave_stop_pos = <0>; lcd_sync_pixel_num = <0>; lcd_sync_line_num = <0>; }; &lcd1 { lcd_used = <1>; lcd_driver_name = "lpm025m475a"; ;lcd_bl_0_percent = <0>; ;lcd_bl_40_percent = <23>; ;lcd_bl_100_percent = <100>; lcd_backlight = <50>; lcd_if = <4>; lcd_x = <1080>; lcd_y = <1920>; lcd_width = <31>; lcd_height = <56>; lcd_dclk_freq = <141>; lcd_pwm_used = <1>; lcd_pwm_ch = <0>; lcd_pwm_freq = <20000>; lcd_pwm_pol = <0>; lcd_pwm_max_limit = <255>; lcd_hbp = <100>; lcd_ht = <1212>; lcd_hspw = <5>; lcd_vbp = <8>; lcd_vt = <1936>; lcd_vspw = <2>; lcd_dsi_if = <0>; lcd_dsi_lane = <4>; lcd_dsi_format = <0>; lcd_dsi_te = <0>; lcd_dsi_eotp = <0>; lcd_frm = <0>; lcd_io_phase = <0x0000>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; lcd_dsi_port_num = <0>; lcd_tcon_mode = <1>; lcd_tcon_slave_num = <0>; lcd_slave_stop_pos = <0>; lcd_sync_pixel_num = <0>; lcd_sync_line_num = <0>; lcd_bl_en = <&pio PH 10 1 0 3 1>; lcd_power = "vcc-dsi"; lcd_power1 = "vcc18-lcd"; lcd_power2 = "vcc33-lcd"; lcd_gpio_0 = <&pio PH 8 1 0 3 1>; lcd_gpio_1 = <&pio PH 11 1 0 3 1>; lcd_gpio_2 = <&pio PH 12 1 0 3 1>; lcd_pin_power = "vcc-ph" };
4.5 I8080 接口
4.5.1 概述
Intel 8080 接口屏(又稱MCU 接口) 很老的協議,一般用在分辨率很小的屏上。
信號線:
? CS 片選信號,決定該芯片是否工作。
? RS 寄存器選擇信號,低表示選擇index 或者status 寄存器,高表示選擇控制寄存器。實際場景中一般接SoC 的LCD_DE 腳(數據使能腳)。
? /WR (低表示寫數據) 數據命令區分信號,也就是寫時鐘信號,一般接SoC 的LCD_CLK 腳。
? /RD (低表示讀數據)數據讀信號,也就是讀時鐘信號,一般接SoC 的LCD_HSYNC 腳。
? RESET 復位LCD(用固定命令系列0 1 0 來復位)。
? Data 雙向傳輸的數據總線。
I8080 根據的數據位寬接口有8/9/16/18,連哪些腳參考,即使位寬一樣,連的管腳也不一樣,還要考慮的因素是rgb 格式。
RGB565,總共有65K 這么多種顏色。
RGB666,總共有262K 那么多種顏色。
9bit 固定為262K。
從屏手冊得知:數據位寬,顏色數量之和,參考RGB 和I8080 管腳配置示意圖,進行硬件連接。
4.5.2 I8080 接口屏典型配置示例
下面是典型是一個RGB565 的,位寬為8 位的I8080 接口的屏的board.dts 配置示例
1.第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏驅動來初始化。
2.第二部分,決定該配置是I8080 接口,而且是8bit/2cycle 格式RGB565。
技巧 為什么叫做8bit/2cycle RGB565 呢,首先它的格式是RGB565,也就是一個像素是16bit,然后它是8bit 的位寬,就需要兩個時鐘周期才能發完一個像素,所以才
叫2 cycle。
第三部分,決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。這里比較特殊的是設置像素時鐘要滿足以下公式:lcd_dclk_freq2>=lcd_htlcd_vt*fps,或者lcd_dclk_freq=lcd_ht 2lcd_vt*60, 也就是要么雙倍lcd_ht要么雙倍lcd_dclk_freq。
第四部分,背光相關的設置。請看背光相關參數。
第五部分,cpu 接口的詳細設置。這里使能了lcd_cpu_te和lcd_cpu_mode,意思是使用te觸發和規定了觸發間隔。這是非常關鍵的設置。
第六部分,顯示效果相關的設置。這里使能了lcd_frm也是比較關鍵的設置,詳細意思點擊查看。
第七部分,管腳和電源設置。這里為了用te 觸發,同樣需要設置lcd_vsync,該腳功能定義已經包括在pinctrl-0 中。這里自定義了一組管腳。參考RGB 和
I8080 管腳配置示意圖,通過確定I8080 的位寬,像素格式(顏色數量),在表中確定需要連接哪些管腳。請看電源和管腳參數。
&pio { I8080_8bit_pins_a: I8080_8bit@0 { allwinner,pins = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,pname = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,function = "I8080_8bit"; allwinner,muxsel = <2>; allwinner,drive = <3>; allwinner,pull = <0>; }; I8080_8bit_pins_b: I8080_8bit@1 { allwinner,pins = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,pname = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,function = "I8080_8bit_suspend"; allwinner,muxsel = <7>; allwinner,drive = <3>; allwinner,pull = <0>; }; }; &lcd0 { /* part 1 */ lcd_used = <1>; lcd_driver_name = "s2003t46g"; /* part 2 */ lcd_if = <1>; lcd_cpu_if = <14>; /* part 3 */ lcd_x = <240>; lcd_y = <320>; lcd_width = <108>; lcd_height = <64>; lcd_dclk_freq = <16>; lcd_hbp = <20>; lcd_ht = <298>; lcd_hspw = <10>; lcd_vbp = <8>; lcd_vt = <336>; lcd_vspw = <4>; /* part 4 */ lcd_pwm_used = <1>; lcd_pwm_ch = <8>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_bright_curve_en = <1>; /* part 5 */ lcd_cpu_mode = <1>; lcd_cpu_te = <1>; /* part 6 */ lcd_frm = <1>; lcd_gamma_en = <0>; lcd_cmap_en = <0>; lcd_rb_swap = <0>; /* part 7 */ lcd_power = "vcc-lcd"; lcd_pin_power = "vcc-pd"; ;reset pin lcd_gpio_0 = <&pio PD 9 1 0 3 1>; ;cs pin lcd_gpio_1 = <&pio PD 10 1 0 3 0>; pinctrl-0 = <&I8080_8bit_pins_a>; pinctrl-1 = <&I8080_8bit_pins_a>; };
4.6 LVDS 接口
4.6.1 概述
LVDS 即Low Voltage Differential Signaling 是一種低壓差分信號接口。
4.6.2 LVDS Single link 典型配置
LVDS 接口,lcd0 對應的lvds 管腳和lcd1 對應的lvds 管腳是固定而且不一樣。
由于lvds 協議不具備傳輸數據之外的能力,一般屏端不需要任何初始化,只需要初始化SoC 端即可。所以這里的lcd_driver_name 依舊是”default_lcd”,當然你可
以為初始化的啟動延時做專門的優化。
下面是典型是single link lvds 屏的board.dts 配置示例,其中用空行把配置分成幾個部分
第一部分,決定該配置是否使用,以及使用哪個屏驅動,lcd_driver_name 決定了用哪個屏 驅動來初始化。
第二部分,決定該配置是lvds 接口,而且是single link。 技巧 如果Dual Link 的屏,那么除了要改lcd_lvds_if 為1 之外,管腳方面還要把lcd1 的管腳一起搬到下面去,也就是總共需要配置PD0 到PD9,和配置PD10 到
PD19 總共二十根腳為lvds 管腳功能(功能3)。當然屏的timing 也是要根據屏來改的。
第三部分,決定了SoC 中的LCD 模塊發送時序,請查看屏時序參數說明。
第四部分,背光相關的設置。請看背光相關參數。
第五部分,lvds 接口的詳細設置。
第六部分,顯示效果相關的設置。
第七部分,管腳和電源設置。請看電源和管腳參數。
&lcd0 { /* part 1 */ lcd_used = 1 lcd_driver_name = "default_lcd"; /* part 2 */ lcd_if = 3 lcd_lvds_if = 0 /* part 3 */ lcd_x = 1280 lcd_y = 800 lcd_width = 150 lcd_height = 94 lcd_dclk_freq = 70 lcd_hbp = 20 lcd_ht = 1418 lcd_hspw = 10 lcd_vbp = 10 lcd_vt = 814 lcd_vspw = 5 /* part 4 */ lcd_pwm_used = 1 lcd_pwm_ch = 0 lcd_pwm_freq = 50000 lcd_pwm_pol = 0 lcd_pwm_max_limit = 255 lcd_backlight = 50 lcd_bright_curve_en = 0 lcd_bl_en = <&pio PD 21 1 0 3 1>; /* part 5 */ lcd_lvds_colordepth = 1 lcd_lvds_mode = 0 /* part 6 */ lcd_frm = 1 lcd_hv_clk_phase = 0 lcd_hv_sync_polarity= 0 lcd_gamma_en = 0 lcd_cmap_en = 0 /* part 7 */ lcd_power = "vcc-lcd" pinctrl-0 = <&lvds0_pins_a>; pinctrl-1 = <&lvds0_pins_b>; };
4.6.3 LVDS dual link 典型配置
如果Dual Link 的屏:
lcd_lvds_if設置為1(場景1)或者2(場景2)。
管腳配置方面,也從4 data lane 變成8 data lane,包括clk lane 總共20 根管腳。
場景1,物理上連接一個屏,8 data lane,SoC 向每4 條lane 傳輸一半的像素,奇數像素或者偶數像素。
&lcd1 { lcd_used = <1>; lcd_driver_name = "bp101wx1"; lcd_backlight = <50>; lcd_if = <3>; lcd_x = <2560>; lcd_y = <800>; lcd_width = <150>; lcd_height = <94>; lcd_dclk_freq = <138>; lcd_pwm_used = <0>; lcd_pwm_ch = <2>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_hbp = <40>; lcd_ht = <2836>; lcd_hspw = <20>; lcd_vbp = <10>; lcd_vt = <814>; lcd_vspw = <5>; lcd_lvds_if = <1>; lcd_lvds_colordepth = <0>; lcd_lvds_mode = <0>; lcd_frm = <0>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; lcd_fsync_en = <0>; lcd_fsync_act_time = <1000>; lcd_fsync_dis_time = <1000>; lcd_fsync_pol = <0>; deu_mode = <0>; lcdgamma4iep = <22>; smart_color = <90>; lcd_bl_en = <&pio PJ 27 1 0 3 1>; lcd_gpio_0 = <&pio PI 1 1 0 3 1>; lcd_pin_power = "bldo5"; lcd_power = "dc1sw"; pinctrl-0 = <&lcd1_lvds2link_pins_a>; pinctrl-1 = <&lcd1_lvds2link_pins_b>; };
場景2(部分IC 支持),物理上連接兩個屏,每個屏各自4 條lane,兩個屏是一樣型號,分辨率和timing 一樣,這時候部分IC 支持將全部像素發到每個屏上,實現
雙顯(信號上的雙顯),注意這時候lcd timing 是一個屏的timing, lcd_lvds_if 為2。
lcd1: lcd1@01c0c001 { lcd_used = <1>; lcd_driver_name = "bp101wx1"; lcd_backlight = <50>; lcd_if = <3>; lcd_x = <1280>; lcd_y = <800>; lcd_width = <150>; lcd_height = <94>; lcd_dclk_freq = <70>; lcd_pwm_used = <0>; lcd_pwm_ch = <2>; lcd_pwm_freq = <50000>; lcd_pwm_pol = <1>; lcd_pwm_max_limit = <255>; lcd_hbp = <20>; lcd_ht = <1418>; lcd_hspw = <10>; lcd_vbp = <10>; lcd_vt = <814>; lcd_vspw = <5>; lcd_lvds_if = <2>; lcd_lvds_colordepth = <0>; lcd_lvds_mode = <0>; lcd_frm = <0>; lcd_hv_clk_phase = <0>; lcd_hv_sync_polarity= <0>; lcd_gamma_en = <0>; lcd_bright_curve_en = <0>; lcd_cmap_en = <0>; lcd_fsync_en = <0>; lcd_fsync_act_time = <1000>; lcd_fsync_dis_time = <1000>; lcd_fsync_pol = <0>; deu_mode = <0>; lcdgamma4iep = <22>; smart_color = <90>; lcd_bl_en = <&pio PJ 27 1 0 3 1>; lcd_gpio_0 = <&pio PI 1 1 0 3 1>; lcd_pin_power = "bldo5"; lcd_power = "dc1sw"; pinctrl-0 = <&lcd1_lvds2link_pins_a>; pinctrl-1 = <&lcd1_lvds2link_pins_a>; };
4.7 RGB 和I8080 管腳配置示意圖
?
圖4-8: pinmux
?
4.8 從sys_config.fex 到board.dtsi 的遷移注意事項
為了規范等原因,部分平臺將配置放在board.dtsi 中實現。下面說明了修改board.dtsi 的注意事項。
4.8.1 管腳定義
在配置RGB 屏或者LVDS 屏時,現在不再需要復雜的定義,也不需要了解到底哪些管腳需要配置,也不需要lcd0_suspend節點了。其中rgb24_pins_a這個名字是
定義好的,直接用即可,一般LCD屏直接可用的配置會在注釋中寫明,你可以在內核目錄下arch/arm/boot/dts或者arch/arm64/boot/dts下的平臺-pinctrl.dtsi 文
件中找。
例子:
pinctrl-0 = <&rgb24_pins_a>; pinctrl-1 = <&rgb24_pins_b>;//休眠時候的定義,io_disable
當然,你也可以自定義一組腳,寫在board.dtsi 中,只要名字不要和現有名字重復就行。
為了規范,我們將在所有平臺保持一致的名字,其中后綴為a 即為管腳使能,b 的為io_disable用于設備關閉時。
目前有以下管腳定義可用:
?
表4-2: 顯示管腳名稱表
?
管腳名稱 | 描述 |
---|---|
rgb24_pins_a 和rgb24_pins_b | RGB 屏接口,而且數據位寬是24,RGB888 |
rgb18_pins_a 和rgb18_pins_b | RGB 屏接口,而且數據位寬是16,RGB666 |
lvds0_pins_a和lvds0_pins_b | Single link LVDS 接口0 管腳定義(主顯lcd0) |
lvds1_pins_a 和lvds1_pins_b | Single link LVDS 接口1 管腳定義(主顯lcd0) |
lvds2link_pins_a 和lvds2link_pins_b | Dual link LVDS 接口管腳定義(主顯lcd0) |
lvds2_pins_a 和lvds2_pins_b | Single link LVDS 接口0 管腳定義(主顯lcd1) |
lvds3_pins_a 和lvds3_pins_b | Single link LVDS 接口1 管腳定義(主顯lcd1) |
lcd1_lvds2link_pins_a 和lcd1_lvds2link_pins_b | Dual link LVDS 接口管腳定義(主顯lcd1) |
dsi4lane_pins_a 和dsi4lane_pins_b | DSI 屏接口管腳定義,4lane,如果是其它lane 數量,只 |
4.8.2 電源定義
電源定義在舊的SDK 中并不需要注意什么,還是直接把axp 的別名字符串賦值給想lcd_power這樣的屬性上即可,但是新的SDK 中,如果需要使用某路電源必須先
在disp 節點中定義,然后lcd 部分使用的字符串則要和disp 中定義的一致。比如下面的例子:
disp: disp@01000000 { disp_init_enable = <1>; disp_mode = <0>; /* VCC-LCD */ dc1sw-supply = ; /* VCC-LVDS and VCC-HDMI */ bldo1-supply = ; /* VCC-TV */ cldo4-supply = ; };
其中”-supply” 是固定的,它之前的字符串則是隨意的,不過建議取有意義的名字。而后面的像 則必須在board.dtsi 的regulator0 節點中找到。
然后lcd0 節點中,如果要使用reg_sw,則類似下面這樣寫就行,dc1sw 對應dc1sw-supply。
lcd_power=”dc1sw”
由于u-boot 中也有axp 驅動和display 驅動,它們和內核一樣,都是讀取同份配置,為了能互相兼容,取名的時候,有以下限制。
在u-boot 2018 中,axp 驅動只認類似bldo1 這樣從axp 芯片中定義的名字,所以命名xxxsupply的時候最好按照這個axp 芯片的定義來命名。
4.8.3 其它注意事項
board.dtsi 里面可能只有lcd0 沒有lcd1,或只有tv0 沒有tv1,這時候你要添加的話,需要參考內核目錄arch/arm/boot/dts 或者arch/arm64/boot/dts 下對應的平
臺.dtsi 文件。其中最關鍵的是@ 后面那串地址必須與內核中定義一致,比如:
lcd1: lcd1@01c0c000
5 硬件參數說明
5.1 LCD 接口參數說明
5.1.1 lcd_driver_name
Lcd 屏驅動的名字(字符串),必須與屏驅動的名字對應。
5.1.2 lcd_model_name
Lcd 屏模型名字,非必須,可以用于同個屏驅動中進一步區分不同屏。
5.1.3 lcd_if
Lcd Interface
設置相應值的對應含義為:
0:HV RGB接口 1:CPU/I80接口 2:Reserved 3:LVDS接口 4:DSI接口
5.1.4 lcd_hv_if
Lcd HV panel Interface
這個參數只有在lcd_if=0 時才有效。定義RGB 同步屏下的幾種接口類型。
設置相應值的對應含義為:
0:Parallel RGB 8:Serial RGB 10:Dummy RGB 11:RGB Dummy 12:Serial YUV (CCIR656)
5.1.5 lcd_hv_clk_phase
Lcd HV panel Clock Phase
這個參數只有在lcd_if=0 時才有效。定義RGB 同步屏的clock 與data 之間的相位關系。總共有4 個相位可供調節。
設置相應值的對應含義為:
0: 0 degree 1: 90 degree 2: 180 degree 3: 270 degree
5.1.6 lcd_hv_sync_polarity
Lcd HV panel Sync signals Polarity
這個參數只有在lcd_if=0 時才有效。定義RGB 同步屏的hsync 和vsync 的極性。
設置相應值的對應含義為:
0:vsync active low,hsync active low 1:vsync active high,hsync active low 2:vsync active low,hsync active high 3:vsync active high,hsync active high
5.1.7 lcd_hv_srgb_seq
Lcd HV panel Serial RGB output Sequence
這個參數只有在lcd_if=0 且lcd_hv_if=8(Serial RGB)時才有效。
定義奇數行RGB 輸出的順序:
0: Odd lines R-G-B; Even line R-G-B 1: Odd lines B-R-G; Even line R-G-B 2: Odd lines G-B-R; Even line R-G-B 4: Odd lines R-G-B; Even line B-R-G 5: Odd lines B-R-G; Even line B-R-G 6: Odd lines G-B-R; Even line B-R-G 8: Odd lines R-G-B; Even line B-R-G 9: Odd lines B-R-G; Even line G-B-R 10: Odd lines G-B-R; Even line G-B-R
5.1.8 lcd_hv_syuv_seq
Lcd HV panel Serial YUV output Sequence
這個參數只有在lcd_if=0 且lcd_hv_if=12(Serial YUV)時才有效。
定義YUV 輸出格式:
0:YUYV 1:YVYU 2:UYVY 3:VYUY
5.1.9 lcd_hv_syuv_fdly
Lcd HV panel Serial YUV F line Delay
這個參數只有在lcd_if=0 且lcd_hv_if=12(Serial YUV)時才有效。
定義CCIR656 編碼時F 相對有效行延遲的行數:
0:F toggle right after active video line 1:Delay 2 lines (CCIR PAL) 2:Delay 3 lines (CCIR NTSC)
5.1.10 lcd_cpu_if
Lcd CPU panel Interface
這個參數只有在lcd_if=1 時才有效, 具體時序可參照RGB 和I8080 管腳配置示意圖中CPU 那幾列。
設置相應值的對應含義為:
0:18bit/1cycle (RGB666) 2: 16bit/3cycle (RGB666) 4:16bit/2cycle (RGB666) 6:16bit/2cycle (RGB666) 8:16bit/1cycle (RGB565) 10:9bit/1cycle (RGB666) 12:8bit/3cycle (RGB666) 14:8bit/2cycle (RGB565)
5.1.11 lcd_cpu_te
Lcd CPU panel tear effect
設置相應值的對應含義為,設置為0 時,刷屏間隔時間為lcd_ht × lcd_vt;設置為1 或2 時,刷屏間隔時間為兩個te 脈沖:
Lcd CPU panel tear effect
設置相應值的對應含義為,設置為0 時,刷屏間隔時間為lcd_ht × lcd_vt;設置為1 或2 時,刷屏間隔時間為兩個te 脈沖:
0:frame trigged automatically 1:frame trigged by te rising edge 2:frame trigged by te falling edge
5.1.12 lcd_lvds_if
Lcd LVDS panel Interface
設置相應值的對應含義為:
0:Single Link( 1 clock pair+3/4 data pair) 1:Dual Link(8 data lane,每4條lane接受一半像素,奇數像素或者偶數像素) 2: Dual Link (每4條lane接受全部像素,常用于物理雙屏,且兩個屏一樣)
lcd_lvds_if 等于2 的場景是,接兩個一模一樣的屏,然后兩個屏顯示同樣的內容,此時lcd 的其它timing 只需要填寫一個屏的timing 即可。
5.1.13 lcd_lvds_colordepth
Lcd LVDS panel color depth
設置相應值對應含義為:
0:8bit per color(4 data pair) 1:6bit per color(3 data pair)
5.1.14 lcd_lvds_mode
Lcd LVDS Mode
這個參數只有在lcd_lvds_bitwidth=0 時才有效。
設置相應值對應含義為(見下圖):
0:NS mode 1:JEIDA mode
?
圖5-1: lvds mode
?
5.1.15 lcd_dsi_if
Lcd MIPI DSI panel Interface
這個參數只有在lcd_if=4 時才有效。定義MIPI DSI 屏的兩種類型。
設置相應值的對應含義為:
0:Video mode 1:Command mode 2:video burst mode
注:Video mode 的LCD 屏,是實時刷屏的,有ht,hbp 等時序參數的定義;Command mode 的屏,屏上帶有顯示Buffer,一般會有一個TE 引腳。
5.1.16 lcd_dsi_lane
Lcd MIPI DSI panel Data Lane number
這個參數只有在lcd_if=4 時才有效。
設置相應值的對應含義為:
1:1 data lane 2:2 data lane 3:3 data lane 4:4 data lane
5.1.17 lcd_dsi_format
Lcd MIPI DSI panel Data Pixel Format
這個參數只有在lcd_if=4 時才有效。
設置相應值的對應含義為:
0:Package Pixel Stream, 24bit RGB 1:Loosely Package Pixel Stream, 18bit RGB 2:Package Pixel Stream, 18bit RGB 3:Package Pixel Stream, 16bit RGB
5.1.18 lcd_dsi_te
Lcd MIPI DSI panel Tear Effect
這個參數只有在lcd_if=4 時才有效。
設置相應值的對應含義為:
0:frame trigged automatically 1:frame trigged by te rising edge 2:frame trigged by te falling edge
注:設置為0 時,刷屏間隔時間為lcd_ht × lcd_vt;設置為1 或2 時,刷屏間隔時間為兩個te脈沖。
這個的作用就是屏一端發給SoC 端的信號,用于同步信號,如果使能這個變量,那么SoC 內部的顯示中斷將由這個外部腳來觸發。
5.1.19 lcd_dsi_port_num
DSI 屏port 數量
這個參數只有在lcd_if=4 時才有效。
設置相應值的對應含義為:
0:一個port 1:兩個port
這個選項的一個作用是,單LCD 屏為8 條lane 的時候,如果只需要初始化其中一個driver IC,則這個設置1,如果兩個driver IC 都要初始化,這里設置成0。并使用lcd_source.c 定義的函數來進行初始化。
5.1.20 lcd_tcon_mode
Tcon 模式
這個參數只有在lcd_if=4 時才有效。
設置相應值的對應含義為:
0:normal mode 1:tcon master mode(在第一次發送數據同步) 2::tcon master mode(每一幀都同步) 3:tcon slave mode(依靠master mode來啟動) 4:one tcon driver two dsi(8條lane) 5.1.21 lcd_slave_tcon_num
5.1.21 lcd_slave_tcon_num
Slave Tcon 的序號
這個參數只有在lcd_if=4 時而且lcd_tcon_mode 等于1 或者2 才有效。用于告訴master 模式下的tcon,從tcon 的序號是多少。
設置相應值的對應含義為:
0:tcon_lcd0 1:tcon_lcd1
5.1.22 lcd_tcon_en_odd_even_div
這個參數只有在lcd_if=4 而且lcd_tcon_mode=4 時才有效。
設置相應值的對應含義為:
0:tcon將一幀圖像分左右兩半來發送給兩個DSI模塊 1:tcon將一幀圖像分奇偶像素來發給兩個DSI模塊
5.1.23 lcd_sync_pixel_num
這個參數只有在lcd_if=4 而且lcd_tcon_mode 等于2 或者3 時才有效。
設置同步從tcon 的起始pixel。
整數:不超過lcd_ht
5.1.24 lcd_sync_line_num
這個參數只有在lcd_if=4 而且lcd_tcon_mode 等于2 或者3 時才有效。
設置同步從tcon 的起始行。
整數:不超過lcd_vt
5.1.25 lcd_cpu_mode
Lcd CPU 模式,控制。
設置相應值的對應含義為,設置為0 時,刷屏間隔時間為lcd_ht × lcd_vt;設置為1 或2 時,刷屏間隔時間為兩個te 脈沖:
0:中斷自動根據時序,由場消隱信號內部觸發。 1:中斷根據數據Block的counter觸發或者由外部te觸發。
5.1.26 lcd_fsync_en
LCD 使能fsync 功能,用于觸發sensor 出圖, 目的是同步,部分IC 支持。
0:disable 1:enable
5.1.27 lcd_fsync_act_time
LCD 的fsync 功能,其中的有效電平時間長度,單位:像素時鐘的個數。
0~lcd_ht-1
5.1.28 lcd_fsync_dis_time
LCD 的fsync 功能,其中的無效電平時間長度,單位:像素時鐘的個數。
0~lcd_ht-1
5.1.29 lcd_fsync_pol
LCD 的fsync 功能的有效電平的極性。
0:有效電平為低 1:有效電平為高
5.2 屏時序參數說明
下面幾個參數對于調屏非常關鍵,決定了發送端(SoC)發送數據時序。由于涉及到發送端和接收端的調試,除了分辨率和尺寸之外,其它幾個數值都不是絕對不
變的,兩款一樣分辨率,同種接口的屏,它們的數值也有可能不一樣。
獲取途徑如下:
詢問LCD 屏廠。
從屏手冊或者Driver IC 手冊中查找(向屏廠索要這些文檔),如下圖所示。
?
圖5-2: lcd_info1
?
?
圖5-3: lcd_info2
?
在前面兩步都搞不定的情況下,可以根據vesa 標準來設置,主要是DMT 和CVT 標準。
其中DMT,指的是《VESA and Industry Standards and Guidelines for Computer Display Monitor Timing(DMT)》,下載該標準,里面就有各種常用分辨率的
timing。其中的CVT,指的是《VESA Coordinated Video Timings(CVT) Standard》,該標準提供一種通用公式用于計算出指定分辨率,刷新率等參數的timing。
可以下載這個excel 表來計算VESA Coordinated Video Timing Generator。
由下面兩條公式得知,我們不需要設置lcd_hfp和lcd_vfp參數,因為驅動會自動根據其它幾個已知參數中算出lcd_hfp和lcd_vfp。
lcd_ht = lcd_x + lcd_hspw + lcd_hbp + lcd_hfp lcd_vt = lcd_y + lcd_vspw + lcd_vbp + lcd_vfp
5.2.1 lcd_x
顯示屏的水平像素數量,也就是屏分辨率中的寬。
5.2.2 lcd_y
顯示屏的垂直行數,也就是屏分辨率中的高。
5.2.3 lcd_ht
Horizontal Total time
指一行總的dclk 的cycle 個數。見下圖:
?
圖5-4: lcdht
?
5.2.4 lcd_hbp
Horizontal Back Porch
指有效行間,行同步信號(hsync)開始,到有效數據開始之間的dclk 的cycle 個數,包括同步信號區。見上圖,注意的是包含了hspw 段。
說明 是包含了hspw 段,也就是lcd_hbp= 實際的hbp+ 實際的hspw
5.2.5 lcd_hspw
Horizontal Sync Pulse Width
指行同步信號的寬度。單位為1 個dclk 的時間(即是1 個data cycle 的時間)。見上圖。
5.2.6 lcd_vt
Vertical Total time
指一場的總行數。見下圖:
?
圖5-5: lcdvt
?
5.2.7 lcd_vbp
Vertical Back Porch
指場同步信號(vsync)開始,到有效數據行開始之間的行數,包括場同步信號區。
說明
是包含了vspw 段,也就是lcd_vbp= 實際的vbp+ 實際的vspw
5.2.8 lcd_vspw
Vertical Sync Pulse Width
指場同步信號的寬度。單位為行。見上圖。
5.2.9 lcd_dclk_freq
Dot Clock Frequency
傳輸像素傳送頻率。單位為MHz。
fps = (lcd_dclk_freq×1000×1000) / (ht×vt)。
這個值根據以下公式計算:
lcd_dclk_freq=lcd_htlcd_vtfps
注意:
后面的三個參數都是從屏手冊中獲得,fps 一般是60。
如果是串行接口,發完一個像素需要2 到3 個周期的,那么。
lcd_dclk_freq * cycles = lcd_ht*lcd_vt*fps
或者
lcd_dclk_freq = lcd_ht*cycles*lcd_vt*fps
5.2.10 lcd_width
Width of lcd panel in mm
此參數描述lcd 屏幕的物理寬度,單位是mm。用于計算dpi。
5.2.11 lcd_height
height of lcd panel in mm
此參數描述lcd 屏幕的物理高度,單位是mm。用于計算dpi。
5.3 背光相關參數
目前用得比較廣泛的就是pwm 背光調節,原理是利用pwm 脈沖開關產生的高頻率閃爍效應,通過調節占空比,達到欺騙人眼,調節亮暗的目的。
5.3.1 lcd_pwm_used
是否使用pwm。
此參數標識是否使用pwm 用以背光亮度的控制。
5.3.2 lcd_pwm_ch
Pwm channel used
此參數標識使用的Pwm 通道,這里是指使用SoC 哪個pwm 通道,通過查看原理圖連接可知。
5.3.3 lcd_pwm_freq
Lcd backlight PWM Frequency
這個參數配置PWM 信號的頻率,單位為Hz。
說明 頻率不宜過低否則很容易就會看到閃爍,頻率不宜過快否則背光調節效果差。部分屏手冊會標明所允許的pwm 頻率范圍,請遵循屏手冊固定范圍進行設置。 在低亮度的時候容易看到閃爍,是正常現象,目前已知用上pwm 的背光都是如此。
5.3.4 lcd_pwm_pol
Lcd backlight PWM Polarity
這個參數配置PWM 信號的占空比的極性。設置相應值對應含義為:
0:active high 1:active low
5.3.5 lcd_pwm_max_limit
Lcd backlight PWM 最高限制,以亮度值表示
比如150,則表示背光最高只能調到150,0-255 范圍內的亮度值將會被線性映射到0-150 范圍內。用于控制最高背光亮度,節省功耗。
5.3.6 lcd_bl_en
背光使能腳,非必須,看原理圖是否有,用于使能或者禁止背光電路的電壓。
示例:lcd_bl_en = port:PD24<1><2><1>
含義:PD24 輸出高電平時打開LCD 背光;下拉,默認高電平
? 第一個尖括號:功能分配;1 為輸出;
? 第二個尖括號:內置電阻;使用0 的話,標示內部電阻高阻態,如果是1 則是內部電阻上拉,2 就代表內部電阻下拉。使用default 的話代表默認狀態,即電阻上
拉。其它數據無效。
? 第三個尖括號:驅動能力;default 表驅動能力是等級1
? 第四個尖括號:電平;0 為低電平,1 為高電平。
需要在屏驅動調用相應的接口進行開、關的控制。
說明
一般來說,高電平是使能,在這個前提下,建議將內阻電阻設置成下拉,防止硬件原因造成的上拉,導致背光提前亮。默認電平請填寫高電平,這是uboot 顯示過
度到內核顯示,平滑無閃爍的需要。
5.3.7 lcd_bl_n_percent
背光映射值,n 為(0-100)
此功能是針對亮度非線性的LCD 屏的,按照配置的亮度曲線方式來調整亮度變化,以使亮度變化更線性。
比如lcd_bl_50_percent = 60,表明將50% 的亮度值調整成60%,即亮度比原來提高10%。
說明
修改此屬性不當可能導致背光調節效果差。
5.3.8 lcd_backlight
背光默認值,0-255。
此屬性決定在uboot 顯示logo 階段的亮度,進入都內核時則是讀取保存的配置來決定亮度。
說明
顯示logo 階段,一般來說需要比較亮的亮度,業內做法都是如此。
5.4 顯示效果相關參數
5.4.1 lcd_frm
Lcd Frame Rate Modulator
FRM 是解決由于PIN 減少導致的色深問題。
這個參數設置相應值對應含義為:
0:RGB888 -- RGB888 direct 1:RGB888 -- RGB666 dither 2:RGB888 -- RGB565 dither
有些LCD 屏的像素格式是18bit 色深(RGB666)或16bit 色深(RGB565),建議打開FRM功能,通過dither 的方式彌補色深,使顯示達到24bit 色深(RGB888)
的效果。如下圖所示,上圖是色深為RGB66 的LCD 屏顯示,下圖是打開dither 后的顯示,打開dither 后色彩漸變的地方過度平滑。
?
圖5-6: lcd_frm 打開
?
?
圖5-7: lcd_frm 關閉
?
5.4.2 lcd_gamma_en
Lcd Gamma Correction Enable
設置相應值的對應含義為:
0:Lcd的Gamma校正功能關閉 1:Lcd的Gamma校正功能開啟
設置為1 時,需要在屏驅動中對lcd_gamma_tbl[256] 進行賦值。
5.4.3 lcd_cmap_en
Lcd Color Map Enable
設置相應值的對應含義為:
0:Lcd的色彩映射功能關閉 1:Lcd的色彩映射功能開啟
設置為1 時,需要對lcd_cmap_tbl 2[4] 進行賦值Lcd Color Map Table。
每個像素有R、G、B 三個單元,每四個像素組成一個選擇項,總共有12 個可選。數組第一維表示奇偶行,第二維表示像素的RGB,第三維表示第幾個像素,數組
的內容即表示該位置映射到的內容。
LCD CMAP 是對像素的映射輸出功能,只有像素有特殊排布的LCD 屏才需要配置。
LCD CMAP 定義每行的4 個像素為一個總單元,每個像素分R、G、B 3 個小單元,總共有12個小單元。通過lcd_cmap_tbl 定義映射關系,輸出的每個小單元可隨
意映射到12 個小單元之一。
__u32 lcd_cmap_tbl[2][3][4] = { { {LCD_CMAP_G0,LCD_CMAP_B1,LCD_CMAP_G2,LCD_CMAP_B3}, {LCD_CMAP_B0,LCD_CMAP_R1,LCD_CMAP_B2,LCD_CMAP_R3}, {LCD_CMAP_R0,LCD_CMAP_G1,LCD_CMAP_R2,LCD_CMAP_G3}, }, { {LCD_CMAP_B3,LCD_CMAP_G2,LCD_CMAP_B1,LCD_CMAP_G0}, {LCD_CMAP_R3,LCD_CMAP_B2,LCD_CMAP_R1,LCD_CMAP_B0}, {LCD_CMAP_G3,LCD_CMAP_R2,LCD_CMAP_G1,LCD_CMAP_R0}, }, };
如上,上三行代表奇數行的像素排布,下三行代表偶數行的像素排布。
每四個像素為一個單元,第一列代表每四個像素的第一個像素映射,第二列代表每四個像素的第二個像素映射,以此類推。
如上的定義,像素的輸出格式如下圖所示。
?
圖5-8: cmap
?
5.4.4 lcd_rb_swap
調換tcon 模塊RGB 中的R 分量和B 分量。
0:不變 1:調換R分量和B分量
5.5 電源和管腳參數
5.5.1 概述
如果需要使用某路電源必須現在[disp]節點中定義,然后[lcd]部分使用的字符串則要和disp 中定義的一致。比如下面的例子:
disp: disp@01000000 { disp_init_enable = <1>; disp_mode = <0>; /* VCC-LCD */ dc1sw-supply = ; /* VCC-LVDS and VCC-HDMI */ bldo1-supply = ; /* VCC-TV */ cldo4-supply = ; };
其中-supply是固定的,在-supply之前的字符串則是隨意的,不過建議取有意義的名字。在=后面的像則必須在board.dtsi 的regulator0節點中找到。
然后lcd0 節點中,如果要使用reg_sw,則像下面這樣寫就行,dc1sw 對應dc1sw-supply。
lcd_power=”dc1sw”
由于u-boot 中也有axp 驅動和display 驅動,和內核,它們都是讀取同份配置,為了能互相兼容,取名的時候,有以下限制:
在u-boot 2018 中,axp 驅動只認類似bldo1 這樣從axp 芯片中定義的名字,所以命名xxxsupply的時候最好按照這個axp 芯片的定義來命名。
5.5.2 lcd_power
見上面概述的注意事項。
示例:lcd_power = “vcc-lcd”
配置regulator 的名字。配置好之后,需要在屏驅動調用相應的接口進行開、關的控制。
注意:如果有多個電源需要打開,則定義lcd_power1,lcd_power2 等。
5.5.3 lcd_pin_power
用法lcd_power一致,區別是用戶設置之后,不需要在屏驅動中去操作,而是驅動框架自行在屏驅動之前使能,在屏驅動之后禁止。
示例:lcd_pin_power = “vcc-pd”
注意:如果需要多組,則添加lcd_pin_power1,lcd_pin_power2 等。除了lcddx 之外,這里的電源還有可能是pwm 所對應管腳的電源。
5.5.4 lcd_gpio_0
示例:lcd_gpio_0 = port:PD25<0><0><0>
含義:lcd_gpio_0 引腳為PD25。
? 第一個尖括號:功能分配;0 為輸入,1 為輸出。
? 第二個尖括號:內置電阻;使用0 的話,標示內部電阻高阻態,如果是1 則是內部電阻上拉,2 就代表內部電阻下拉。使用default 的話代表默認狀態,即電阻上
拉。其它數據無效。
? 第三個尖括號:驅動能力;default 表驅動能力是等級1。
? 第四個尖括號:表示默認值;即是當設置為輸出時,該引腳輸出的電平,0 為低電平,1 為高電平。
需要在屏驅動調用相應的接口進行拉高,拉低的控制。請看管腳控制函數說明
注意:如果有多個gpio 腳需要控制,則定義lcd_gpio_0,lcd_gpio_1 等。
5.5.5 lcddx
示例:lcdd0 = port:PD00<3><0>
含義:lcdd0 這個引腳,即是PD0,配置為LVDS 輸出。
? 第一個尖括號:功能分配;0 為輸入,1 為輸出,2 為LCD 輸出,3 為LVDS 接口輸出,7 為disable。
? 第二個尖括號:內置電阻;使用0 的話,標示內部電阻高阻態,如果是1 則是內部電阻上拉,2 就代表內部電阻下拉。使用default 的話代表默認狀態,即電阻上
拉。其它數據無效。
? 第三個尖括號:驅動能力;default 表驅動能力是等級1。
? 第四個尖括號:表示默認值;即是當設置為輸出時,該引腳輸出的電平,0 為低電平,1 為高電平。
LCD PIN 的配置如下:
LCD 為HV RGB 屏,CPU/I80 屏時,必須定義相應的IO 口為LCD 輸出(如果是0 路輸出,第一個尖括號為2;如果是1 路輸出,第一個尖括號為3)。
具體的IO 對應關系可參考user manual 手冊進行配置。
LCD PIN 的所有IO,均可通過注釋方式去掉其定義,顯示驅動對注釋IO 不進行初始化操作。
需要在屏驅動調用相應的接口進行開、關的控制。
注意:不是一定要叫做lcdd0 這個名字,你改成其它名字對驅動不會造成任何影響,這里只是為了方便記憶。
5.5.6 pinctrl-0 和pinctrl-1
在配置lcd0節點時,當碰到需要配置管腳復用時,你只要把pinctrl-0和pinctrl-1賦值好就行,可以用提前定義好的,也可以用自己定義的,提前定義的管腳一般可
以在內核目錄下arch/arm/boot/dts或者arch/arm64/boot/dts下找:平臺-pinctrl.dtsi 中找到定義。
例子:
pinctrl-0 = <&rgb24_pins_a>; pinctrl-1 = <&rgb24_pins_b>;//休眠時候的定義,io_disable
?
表5-1: 提前定義好的管腳名稱
?
管腳名稱 | 描述 |
---|---|
rgb24_pins_a 和rgb24_pins_b | RGB 屏接口,而且數據位寬是24,RGB888 |
rgb18_pins_a 和rgb18_pins_b | RGB 屏接口,而且數據位寬是16,RGB666 |
lvds0_pins_a 和lvds0_pins_b | Single link LVDS 接口0 管腳定義(主顯lcd0) |
lvds1_pins_a 和lvds1_pins_b | Single link LVDS 接口1 管腳定義(主顯lcd0) |
lvds2link_pins_a 和lvds2link_pins_b | Dual link LVDS 接口管腳定義(主顯lcd0) |
lvds2_pins_a 和lvds2_pins_b | Single link LVDS 接口0 管腳定義(主顯lcd1) |
lvds3_pins_a 和lvds3_pins_b | Single link LVDS 接口1 管腳定義(主顯lcd1) |
lcd1_lvds2link_pins_a 和lcd1_lvds2link_pins_b | Dual link LVDS 接口管腳定義(主顯lcd1) |
dsi4lane_pins_a 和dsi4lane_pins_b | 4 lane DSI 屏接口管腳定義 |
自定義一組腳
寫在board.dtsi 中,只要名字不要和現有名字重復就行,首先判斷自己需要用的管腳,屬于大cpu 域還是小cpu 域,以此判斷需要將管腳定義放在pio(大cpu
域)下面還是r_pio(小cpu域)下面。
例子:
&pio { I8080_8bit_pins_a: I8080_8bit@0 { allwinner,pins = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,pname = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,function = "I8080_8bit"; allwinner,muxsel = <2>; allwinner,drive = <3>; allwinner,pull = <0>; }; I8080_8bit_pins_b: I8080_8bit@1 { allwinner,pins = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,pname = "PD1", "PD2", "PD3", "PD4", "PD5", "PD6", "PD7", "PD8", "PD18", " PD19", "PD20", "PD21"; allwinner,function = "I8080_8bit_suspend"; allwinner,muxsel = <7>; allwinner,drive = <3>; allwinner,pull = <0>; }; };
? pins,具體管腳。
? pname,管腳名稱,隨便取。
? function,管腳功能名稱,隨便取。
? muxsel,管腳功能選擇。根據port spec 來選擇對應功能。
? drive,驅動能力,數值越大驅動能力越大。
? pull,上下拉,使用0 的話,標示內部電阻高阻態,如果是1 則是內部電阻上拉,2 就代表內部電阻下拉。使用default 的話代表默認狀態,即電阻上拉。其它數
據無效。
為了規范,我們將在所有平臺保持一致的名字,其中后綴為a 為管腳使能,b 的為io_disable 用于設備關閉時。
有時候,你需要用兩組不同功能的管腳,可以像下面這樣定義即可。
pinctrl-0 = <&rgb24_pins_a>, <&xxx_pins_a>; pinctrl-1 = <&rgb24_pins_b>, <&xxx_pins_b>;//休眠時候的定義,io_disable
5.6 ESD 靜電檢測自動恢復功能
這個功能在linux4.9 以及linux 3.10 sunxi-product 分支上實現了,如果需要這個功能,需要完成以下步驟。
首先打開如下內核配置:
?
圖5-9: ESD 內核配置
?
修改屏驅動,實現三個回調函數:
如下示例,在屏he0801a068 上添加esd 相關的回調函數。 (linux-4.9/drivers/video/fbdev/sunxi/disp2/disp/lcd/he0801a068.c)。
?
圖5-10: ESD 屏驅動添加函數
?
esd_check 函數原型:
S32 esd_check(u32 sel)
作用:是給上層反饋當前屏的狀態。
返回值:如果屏正常的話就返回0,不正常的話就返回非0。
sel:顯示索引。
由于屏的類型接口眾多,不同屏檢測屏的狀態各異,一般來說是通過驅動接口讀取屏的內部信息(id 或者其它寄存器),如果獲取正常則認為屏是正常的,獲取失
敗則認為屏是異常的。比如下面dsi 屏的做法:
?
圖5-11: ESD 屏驅動函數實現
?
此外,一般情況下,也會通過dsi 接口讀取0x0A 命令(獲取power 模式)來判斷屏是否正常。
sunxi_lcd_dsi_dcs_read(sel, 0x0A, result, &num)
?
圖5-12: ESD MIPI 狀態寄存器
?
reset_panel 函數原型:
s32 reset_panel(u32 sel)
作用:當屏幕異常的時候所需要的復位操作。
返回值:復位成功就是0,復位失敗非0。
sel:顯示索引。
每個屏的初始化都不同,順序步驟都不一樣,總的來說就是執行部分或者完整的屏驅動里面的close_flow 和open_flow 所定義的回調函數。根據實際情況靈活編寫
這個函數。
值得注意的是:某些dsi 屏中,需要至少執行過一次sunxi_lcd_dsi_clk_disable(dsi 高速時鐘禁止)和sunxi_lcd_dsi_clk_enable(高速時鐘使能),否則可能導致
dsi 的讀函數異常。
下圖是復位函數示例:
?
圖5-13: ESD 復位函數1
?
set_esd_info 函數原型:
s32 set_esd_info(struct disp_lcd_esd_info *p_info)
作用:控制esd 檢測的具體行為。比如間隔多長時間檢測一次,復位的級別,以及檢測函數被調用的位置。
返回值:成功設置返回0,否則非0。
p_info:需要設置的esd 行為結構體。
示例:下面圖所示,每隔60 次顯示中斷檢測一次(調用esd_check 函數,如果顯示幀率是60fps 的話,那么就是1 秒一次),然后將在顯示中斷處理函數里面執行
檢測函數,由esd_check_func_pos 成員決定調用esd_check 函數的位置,如果是0 則在中斷之外執行檢測函數,之所以有這個選項是因為顯示中斷資源(中斷處
理時間)是非常珍貴的資源,關系到顯示幀率的問題。下圖中的level 為1 表示復位全志SoC 的LCD 相關模塊以及reset_panel 里面的操作,level 為0 的時候表示
僅僅執行reset_panel 里面的操作。
?
圖5-14: ESD 設置信息函數
?
可以通過cat /sys/class/disp/disp/attr/sys 獲取當前的esd info。
screen 0: de_rate 594000000 hz, ref_fps:60 mgr0: 2560x1600 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] unblank err[0] force_sync[0] dmabuf: cache[0] cache max[0] umap skip[0] overflow[0] capture: dis req[0] runing[0] done[0,0] lcd output(enable) backlight( 50) fps:60.9 esd level(1) freq(300) pos(1) reset(244) 2560x1600 err:0 skip:0 skip T.O:50 irq:73424 vsync:0 vsync_skip:0 BUF en ch[1] lyr[0] z[0] prem[N] fbd[N] a[globl 255] fmt[ 0] fb [2560,1600;2560,1600;2560,1600] crop[ 0, 0,2560,1600] frame[ 0, 0,2560,1600] addr[98100000,00000000,00000000] right[00000000,00000000,00000000] flags[0x00] trd[0,0] depth[ 0] acquire: 0, 25.5 fps release: 0, 25.5 fps display: 0, 25.5 fps
esd level(1) freq(300) pos(1) reset(244)
esd levele 和freq 和pos 的意思請看上面set_esd_info 函數原型的解釋。
Reset 后面的數字表示屏復位的次數(也就是esd 導致屏掛掉之后,并且成功檢測到并復位的次數)。
此功能可能遇到的問題。
打靜電掛了,但是讀出來的值仍然是正確的,此問題無解。
Dsi 讀操作卡住了,卡在中斷里面了。此問題可能和DSI 的lp 模式下的速率有關系,而lp 的速率又和dclk 的頻率有關系。此時可以嘗試修改de_dsi_28.c() 文件
中的dsi_basic_cfg 函數,如下圖所示紅框所示的寄存器值,這個寄存器是Lp 模式時鐘分頻值,一般來說這個值越小,lp 速率越快,嘗試改小看是否還會卡
住。
?
圖5-15: Lp 模式時鐘分頻值
?
6 調試方法
系統起來之后可以讀取sysfs 一些信息,來協助調試。
6.1 加快調試速度的方法
很明顯,如果你在安卓上調試LCD 屏會比較不方便,安卓編譯時間和安卓固件都太過巨大,每次修改內核后,可能都要經過10 幾分鐘都才能驗證,這樣效率就太
低下了,可用采用如下方法:
使用linux 固件而不是安卓固件。SDK 是支持僅僅編譯linux 固件,一般是配置lichee 或者longan 的時候選擇linux,打包的時候,用lichee 或者longan 根目錄
下的build.sh 來打包就行。因為linux 內核小得多,編譯更快,更方便調試。
使用內核來調試LCD 屏。我們知道Uboot 和內核都需要添加LCD 驅動,這樣才能快速顯示logo,但是uboot 并不方便調試,所以有時候我們需要把uboot 的
顯示驅動關掉,專心調試內核的LCD 驅動,調好之后才移植到uboot,另外這樣做的一個優點是,我可以非常方便的修改lcd timing 而不需要重燒固件。就是
利用uboot 命令的fdt 命令修改device tree。 比如說:
fdt set lcd0 lcd_hbp <40>
更多命令見fdt help。
如何關閉uboot 顯示呢,一般是在uboot 源碼路徑下inlcude/configs/平臺.h 中,注釋掉CONFIG_SUNXI_MODULE_DISPLAY 即可,如果是uboot 2018 則是注釋
掉configs/平臺_defconfig 中CONFIG_DISP2_SUNXI。
6.2 查看顯示信息
以下信息是所有信息中最重要的。
cat /sys/class/disp/disp/attr/sys screen 0: de_rate 297000000 hz, ref_fps:60 mgr0: 1280x800 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] err[0] force_sync[0] unblank direct_show[false] lcd output backlight( 50) fps:60.9 1280x 800 err:0 skip:31 irq:1942 vsync:0 vsync_skip:0 BUF enable ch[1] lyr[0] z[0] prem[N] a[globl 255] fmt[ 8] fb[1280, 800;1280, 800;1280, 800] crop[ 0, 0,1280, 800] frame[ 0, 0,1280, 800] addr[ 0, 0, 0] flags[0x 0] trd[0,0]
lcd output
表示當前顯示接口是LCD 輸出。
1280x800
表示當前LCD 的分辨率,與board.dts 中lcd0 的設置一樣。
ref_fps:60
是根據你在board.dts的lcd0填的時序算出來的理論值。
fps:60.9
后面的數值是實時統計的,正常來說應該是在60(期望的fps) 附近,如果差太多則不正常,重新檢查屏時序,和在屏驅動的初始化序列是否有被調用到。
irq:1942
這是vsync 中斷的次數,每加1 都代表刷新了一幀,正常來說是一秒60(期望的fps)次,重復cat sys,如果無變化,則異常。
BUF
開頭的表示圖層信息,一行BUF 表示一個圖層,如果一個BUF 都沒有出現,那么將是黑屏,不過和屏驅動本身關系就不大了,應該查看應用層& 框架層。
err:0
這個表示缺數,如果數字很大且一直變化,屏幕會花甚至全黑,全紅等。
skip:31
這個表示跳幀的數量,如果這個數值很大且一直變化,有可能卡頓,如果數字與irq 后面的數字一樣,說明每一幀都跳,會黑屏(有背光)。
6.3 查看電源信息
查看axp 某一路電源是否有enable 可以通過下面命令查看。當然這個只是軟件的,實際還是用萬用表量為準。
cat /sys/class/regulator/dump pmu1736_ldoio2 : disabled 0 700000 supply_name: pmu1736_ldoio1 : disabled 0 700000 supply_name: pmu1736_dc1sw : enabled 1 3300000 supply_name: vcc-lcd pmu1736_cpus : enabled 0 900000 supply_name: pmu1736_cldo4 : disabled 0 700000 supply_name: pmu1736_cldo3 : disabled 0 700000 supply_name: pmu1736_cldo2 : enabled 1 3300000 supply_name: vcc-pf pmu1736_cldo1 : disabled 0 700000 supply_name: pmu1736_bldo5 : enabled 2 1800000 supply_name: vcc-cpvin vcc-pc pmu1736_bldo4 : disabled 0 700000 supply_name: pmu1736_bldo3 : disabled 0 700000 supply_name: pmu1736_bldo2 : disabled 0 700000 supply_name: pmu1736_bldo1 : disabled 0 700000 supply_name: pmu1736_aldo5 : enabled 0 2500000 supply_name: pmu1736_aldo4 : enabled 0 3300000 supply_name: pmu1736_aldo3 : enabled 1 1800000 supply_name: avcc pmu1736_aldo2 : enabled 0 1800000 supply_name: pmu1736_aldo1 : disabled 0 700000 supply_name: pmu1736_rtc : enabled 0 1800000 supply_name: pmu1736_dcdc6 : disabled 0 500000 supply_name: pmu1736_dcdc5 : enabled 0 1480000 supply_name: pmu1736_dcdc4 : enabled 1 900000 supply_name: vdd-sys pmu1736_dcdc3 : enabled 0 900000 supply_name: pmu1736_dcdc2 : enabled 0 1160000 supply_name: pmu1736_dcdc1 : enabled 4 3300000 supply_name: vcc-emmc vcc-io vcc-io vcc-io
6.4 查看pwm 信息
pwm 的用處這里是提供背光電源。
cat /sys/kernel/debug/pwm platform/7020c00.s_pwm, 1 PWM device pwm-0 ((null) ): period: 0 ns duty: 0 ns polarity: normal platform/300a000.pwm, 2 PWM devices pwm-0 (lcd ): requested enabled period: 20000 ns duty: 3984 ns polarity: normal pwm-1 ((null) ): period: 0 ns duty: 0 ns polarity: normal
上面的“requested enabled” 表示請求并且使能了,括號里面的lcd 表示是由lcd 申請的。
6.5 查看管腳信息
cat /sys/kernel/debug/pinctrl/pio/pinmux-pins pin 227 (PH3): twi1 (GPIO UNCLAIMED) function io_disabled group PH3 pin 228 (PH4): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 229 (PH5): (MUX UNCLAIMED) pio:229 pin 230 (PH6): (MUX UNCLAIMED) pio:230 pin 231 (PH7): (MUX UNCLAIMED) pio:231
上面的信息我們知道PH5,PH6 這些IO 被申請為普通GPIO 功能,而PH3 被申請為twi1。
6.6 查看時鐘信息
cat /sys/kernel/debug/clk/clk_summary
這個命令可以看哪個時鐘是否使能,然后頻率是多少。
與顯示相關的是tcon,pll_video,mipi 等等。
cat /sys/kernel/debug/clk/clk_summary | grep tcon cat /sys/kernel/debug/clk/clk_summary | grep pll_video cat /sys/kernel/debug/clk/clk_summary | grep mipi
6.7 查看接口自帶colorbar
顯示是一整條鏈路,中間任何一個環節出錯,最終的表現都是顯示異常,圖像顯示異常幾個可能
原因:
圖像本身異常。
圖像經過DE(Display Engine)后異常。
圖像經過接口模塊后異常。這是我們關注的點。
有一個簡單的方法可以初步判斷,接口模塊(tcon 和dsi 等)可以自己輸出內置的一些patten(比如說彩條、灰階圖、棋盤圖等),當接口輸出這些內置patten
的時候,如果這時候顯示就異常,這說明了:
LCD 的驅動或者配置有問題。
LCD 屏由于外部環境導致顯示異常。
顯示自帶patten 的方式:
在linux-4.9 及其以上版本的內核,disp 的sysfs 中有一個attr 可以直接操作顯示:
echo X > /sys/class/disp/disp/attr/colorbar
上面的操作是顯示colorbar,其中的X 可以是0 到8,對應的含義如下圖所示:
?
圖6-1: colorbar
?
如果有多個顯示設備,想讓第二個顯示設備顯示colorbar 的話,那么先:
echo 1 > /sys/class/disp/disp/attr/disp
然后再執行上面操作。
如果沒有這個attr 的話,可以直接操作寄存器,也就是操作tcon 寄存器的040 偏移的最低3位。
在linux 下,cd /sys/class/sunxi_dump 然后:
echo 0x06511040 > dump;cat dump
這樣會打印當前tcon 的040 偏移寄存器的值,然后在上面值的基礎上修改最低3 位為上圖的值即可,修改方式示例:
echo 0x06511040 0x800001f1 > write
注意tcon 的基地址不一定是0x06511000,不同平臺不一樣,請參考SoC 文檔獲取tcon 的基地址。
6.8 DE 截屏
顯示出現異常的時候,有可能是下面三個原因:
SoC 端屏接口模塊+LCD 屏出現了問題。
圖像經過SoC 端圖像合成模塊(DE)處理后出現了問題。
圖像源本身就有問題。 本節介紹,確認圖像源本身沒問題的前提下,如何進一步確認是否經過DE 處理之后圖像是否有問題。
語法:
echo 屏幕索引> /sys/class/disp/disp/attr/disp echo 路徑/bmp文件名> /sys/class/disp/disp/attr/capture_dump
第一個echo 的作用是確定捕捉哪個顯示的,“屏幕索引” 可選取值是0 或者1。
第二個echo 作用是生成截屏bmp 文件,確保“路徑” 是可寫的,有剩余空間的。
比如:
echo 0 > /sys/class/disp/disp/attr/disp echo /data/xx.bmp > /sys/class/disp/disp/attr/capture_dump
這樣就會在/data 目錄下生成screen 0 的bmp 截圖,文件名是xx.bmp。
除了bmp 之外,還支持保存raw 數據,包括RGB 和YUV 顏色空間,它們以后綴來區分,用法
如下:
# 截取yuv420p顏色空間的raw數據。 echo /data/xx.yuv420_p > /sys/class/disp/disp/attr/capture_dump # 截取yuv420_sp_uvuv顏色空間的raw數據。 echo /data/xx.yuv420_sp_uvuv > /sys/class/disp/disp/attr/capture_dump # 截取yuv420_sp_vuvu顏色空間的raw數據。 echo /data/xx.yuv420_sp_vuvu > /sys/class/disp/disp/attr/capture_dump # 截取yuv420_sp_vuvu顏色空間的raw數據。 echo /data/xx.yuv420_sp_vuvu > /sys/class/disp/disp/attr/capture_dump # 截取argb8888顏色空間的raw數據。 echo /data/xx.argb8888 > /sys/class/disp/disp/attr/capture_dump # 截取abgr8888顏色空間的raw數據。 echo /data/xx.abgr8888 > /sys/class/disp/disp/attr/capture_dump # 截取rgb888顏色空間的raw數據。 echo /data/xx.rgb888 > /sys/class/disp/disp/attr/capture_dump # 截取bgr888顏色空間的raw數據。 echo /data/xx.bgr888 > /sys/class/disp/disp/attr/capture_dump # 截取rgba8888顏色空間的raw數據。 echo /data/xx.rgba8888 > /sys/class/disp/disp/attr/capture_dump # 截取bgra8888顏色空間的raw數據。 echo /data/xx.bgra8888 > /sys/class/disp/disp/attr/capture_dump
注意:這個功能只有linux-4.9 以及后續的內核才支持這個功能。
7 FAQ
7.1 屏顯示異常
總結過往經驗,絕大部分屏顯異常都是由于上下電時序和timing 不合理導致。
請看屏時序參數說明和屏驅動分解。
7.2 黑屏-無背光
問題表現:完全黑屏,背光也沒有。
有兩種可能:
屏驅動添加失敗。驅動沒有加載屏驅動,導致背光電源相關函數沒有運行到。這個你可以通過調試方法定位下。
pwm 配置和背光電路的問題,pwm 的信息可以看pwm 信息和背光相關參數,另外就是直接測量下硬件測量下相關管腳和電壓。
7.3 黑屏-有背光
黑屏但是有背光,可能有多種原因導致,請依次按以下步驟檢查:
沒送圖層。如果應用沒有送任何圖層那么表現的現象就是黑屏,通過查看顯示信息一小節可以確定有沒有送圖層。如果確定沒有圖層,可以通過查看接口自帶
colorbar,確認屏能否正常顯示。
SoC 端的顯示接口模塊沒有供電。SoC 端模塊沒有供電自然無法傳輸視頻信號到屏上。一般SoC 端模塊供電的axp 名字叫做vcc-lcd,vcc-dsi,vcc33-lcd,
vcc18-dsi 等。
復位腳沒有復位。如果有復位腳,請確保硬件連接正確,確保復位腳的復位操作有放到屏驅動中。
board.dts 中lcd0 有嚴重錯誤。第一個是lcd 的timing 太離譜,請嚴格按照屏手冊中的提示來寫!參考屏時序參數說明。第二個就是,接口類型搞錯,比如接
的DSI 屏,配置卻寫成LVDS 的。
屏的初始化命令不對。包括各個步驟先后順序,延時等,這個時候請找屏廠確認初始化命令。
7.4 閃屏
分為幾種:
屏的整體在閃。
這個最大可能是背光電路的電壓不穩定,檢查電壓。
屏部分在閃,而且是概率性。
board.dts 中的時序填寫不合理。
屏上由一個矩形區域在閃。
屏極化導致,需要關機放一邊再開機則不會。
7.5 條形波紋
有些LCD 屏的像素格式是18bit 色深(RGB666)或16bit 色深(RGB565),建議打開FRM功能,通過dither 的方式彌補色深,使顯示達到24bit 色深(RGB888)
的效果。如下圖所示,上圖是色深為RGB66 的LCD 屏顯示,下圖是打開dither 后的顯示,打開dither 后色彩漸變的地方過度平滑。
設置[lcd0] 的lcd_frm 屬性可以改善這種現象。請看lcd_frm解釋。
7.6 背光太亮或者太暗
請看背光相關參數。
7.7 重啟斷電測試屏異常
花屏的第一個原因是fps 過高,超過屏的限制:
FPS 異常是一件非常嚴重的事情,關系到整個操作系統的穩定,如果fps 過高會造成系統帶寬增加,送顯流程異常,fps 過高還會造成LCD 屏花屏不穩定,容易造
成LCD 屏損壞,FPS 過低則造成用戶體驗過差。
通過查看查看顯示信息一節,可以得知現在的實時統計的fps。
如果fps 離正常值差很多,首先檢查board.dts 中[lcd0] 節點,所填信息必須滿足下面公式。
lcd_dclk_freq*num_of_pixel_clk=lcd_ht*lcd_vt*fps /1e9
其中,num_of_pixel_clk 通常為1,表示發送一個像素所需要的時鐘周期為1 一個,低分辨率的MCU 和串行接口通常需要2 到3 個時鐘周期才能發送完一個像素。
如果上面填寫沒有錯,通過查看查看時鐘信息一節可以確認下幾個主要時鐘的頻率信息,把這些信息和board.dts 發給維護者進一步分析。
7.8 RGB 接口或者I8080 接口顯示抖動有花紋
改大時鐘管腳的管腳驅動能力 參考lcd_gpio_0一小節和pinctrl-0 和pinctrl-1,修改驅動能力,改大。
還有另外一種寫法,比如原來是:
lcdclk = port:PD18<2><0><2>
可以改成:
lcdclk = port:PD18<2><0><3>
修改時鐘相位,也就是修改lcd_hv_clk_phase。由于發送端和接收端時鐘相位的不同導致接收端解錯若干位。
7.9 LCD 屏出現極化和殘影
何謂液晶極化現象:實際上就是液晶電介質極化。就是在外界電場作用下,電介質內部沿電場方向產生感應偶極矩,在電解質表明出現極化電荷的現象叫做電介質
的極化。
通俗的講就是在液晶面板施加一定電壓后,會聚集大量電荷,當電壓消失的時候,這些聚集的電荷也要釋放,但由于介電效應,這些聚集的電荷不會立刻釋放消
失,這些不會馬上消失的惰性電荷造成了液晶的DC 殘留從而形成了極化現象。
幾種常見的液晶極化現象
液晶長期靜止某個畫面的時候,切換到灰階畫面的時候出現屏閃,屏閃一段時間后消失。這種現象屬于殘留電荷放電的過程。
液晶長期靜止某個畫面的時候,出現四周發黑中間發白的現象,業內稱為黑白電視框異常。
非法關機的時候,重新上電會出現屏閃,屏閃一定時間后消失。與第一種原因相同。
殘影現象:當液晶靜止在一個畫面比較久的情況下,切換其他畫面出現的鏡像殘留。殘影的本質來說是液晶DC 殘留電荷導致,某種意義來說也屬于液晶極化
現象。
針對液晶屏出現極化和殘影現象,有如下對策。
調整vcom 電壓大小。 VCOM 是液晶分子偏轉的參考電壓,要求要穩定,對液晶顯示有直接影響,具體的屏不同的話也是不同的。電壓的具體值是根據輸入的數據以及Vcom 電壓大
小來確定的,用來顯示各種不同灰階,也就是實現彩色顯示GAMMA。Gamma 電壓是用來控制顯示器的灰階的,一般情況下分為G0~G14,不同的Gamma
電壓與Vcom 電壓之間的壓差造成液晶旋轉角度不同從而形成亮度的差異,Vcom 電壓最好的狀況是位于G0 和G14 的中間值,這樣液晶屏的閃爍狀況會最
好。
調節vcom 電壓的方式,如果屏管腳有vcom 管腳,直接調整相關電路,如果屏driver IC 提供寄存器接口,可以通過寄存器接口來調整大小。
嚴格按照屏規定的上下電時序來對屏進行開關屏。許多極化殘影現象并非長時間顯示靜止顯示某個畫面導致的,而是由于關機或者關屏時沒有嚴格按照下電時
序導致的,比如該關的電沒關,或者延時不夠。
8 總結
調試LCD 顯示屏實際上就是調試發送端芯片(全志SoC)和接收端芯片(LCD 屏上的driver IC)的一個過程:
添加屏驅動請看添加屏驅動步驟和屏驅動說明。
仔細閱讀屏手冊以及driver IC 手冊。
仔細閱讀硬件參數說明。
確保LCD 所需要的各路電源管腳正常。
-
lcd
+關注
關注
34文章
4411瀏覽量
167101 -
Linux
+關注
關注
87文章
11230瀏覽量
208933 -
調試
+關注
關注
7文章
572瀏覽量
33899 -
Display
+關注
關注
1文章
52瀏覽量
24702 -
Tina
+關注
關注
2文章
45瀏覽量
16957
發布評論請先 登錄
相關推薦
評論