ti的lcd控制器驅動是非常完善的,共通的地方已經由驅動封裝好了,與按鍵一樣,我們可以通過dts配置完成lcd的顯示。下面,我們來讨論下使用dts方式配置核心完成lcd驅動的思路。
(1)初步分析
由于tq335x使用的晶片是am335x,故仍然可以參考am335x-evm.dts。當然,am335x-evmsk.dts、am335x-beagbone.dts都可以。本文以am335x-evm.dts為例。大體上浏覽下dts檔案,可以發現兩個醒目的節點:一個是panel,一個是backlight。接下來我們逐個分析。
(2)panel節點資訊分析及配置
從panel節點可以獲得如下資訊:
1. 比對核心驅動的關鍵詞是:"ti,tilcdc,panel",可以通過這個關鍵字找到相應的驅動。
2. 管腳配置在節點lcd_pins_s0内
3. panel-info中可以配置lcd的硬體資訊,如lcd的分辨率等
4. display-times中記錄了lcd刷屏的相關時序。
其中,panel-info和display-times需要去lcd手冊中查找,管腳配置需要根據am335x的晶片手冊、資料手冊及tq335x的原理圖确定,驅動則需要去核心的driver目錄下查找。下面,我一一解決上述幾個問題:
首先是設定panel-info和display-times。我的tq335x是用的我調試tq210時使用的觸摸屏,型号是tn92,這個屏是800*480的分辨率,是以,panel-info與evm開發闆的配置是相同的,可以不做任何修改。但是,不同螢幕的display-times一般是不相同的,是以,需要查閱觸摸屏的手冊來确認display-times。
tn92的水準掃描時序如下表:
垂直掃描時序如下圖:
但是,如果對lcd各參數不怎麼熟悉的話,很難建立這兩個表與dts中display-times的關系,這時應該去查閱一下linux核心的文檔和晶片手冊。在核心文檔:”documentation/devicetree/bindings/video/display-timing.txt"有相關的記載,該檔案中有形象的描述,具體如下:
+----------+-------------------------------------+----------+-------+
| | ↑ | | |
| | |vback_porch | | |
| | ↓ | | |
+----------#######################################----------+-------+
| # ↑ # | |
| # | # | |
| hback # | # hfront | hsync |
| porch # | hactive # porch | len |
|<-------->#<-------+--------------------------->#<-------->|<----->|
| # |vactive # | |
| # ↓ # | |
| | |vfront_porch | | |
| | |vsync_len | | |
am335x的技術參考手冊中可以找到相關的寄存器解釋,如下:
綜合這三份資料,很容易确定下lcd的屏的時序參數的範圍(需要強調的是,上述參數不一定精确,還需要使用圖檔實機測下效果),經過多次實驗,最終确定下了lcd的時序參數,詳情如下:
panel {
compatible = "ti,tilcdc,panel";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&lcd_pins_s0>;
panel-info {
ac-bias = <255>;
ac-bias-intrpt = <0>;
dma-burst-sz = <16>;
bpp = <32>;
fdd = <0x80>;
sync-edge = <0>;
sync-ctrl = <1>;
raster-order = <0>;
fifo-th = <0>;
};
display-timings {
800x480p62 {
clock-frequency = <30000000>;
hactive = <800>;
vactive = <480>;
hfront-porch = <214>;
hback-porch = <40>;
hsync-len = <4>;
vback-porch = <20>;
vfront-porch = <23>;
vsync-len = <4>;
hsync-active = <0>;
vsync-active = <0>;
};
};
時序确定下來之後需要關注的就是管腳配置,由于am335x內建了lcd控制,該控制器與lcd的連接配接方式是通過gpio管腳複用實作的,而evm開發闆與tq335x的lcd都接在了同一個lcd控制器上,是以,直接使用原有的管腳配置即可。這一點也可以通過閱讀tq335x的原理圖确認,這裡我就不再分析了。
(3)backlight節點分析及配置
從backlight節點中可以獲得如下資訊:
1. 比對核心驅動的關鍵詞是"pwm-backlight"。
2. 使用的ecap0進行pwm輸出。
3. 有8個亮度等級。
4. 預設的亮度等級是8,也就是最亮。
了解以上資訊後需要查閱tq335x手冊,弄清楚backlight控制管腳是如何連接配接的。通過分析tq335x的原理圖可知,tq335x的背光控制也是使用pwm方式控制,且該引腳接到am335x的ecap2_in_pwm2_out管腳上,而evm開發闆是接在ecap0_in_pwm0_out管腳上的,是以,需要修改dts配置才能正常使用tq335x的背光功能。思路是将dts中的背光配置由eacp0改為eacp2,下面是修改的步驟:
step1. 将backlight節點中&eacp0改為&eacp2。
step2. 将&epwmss0改為&epwmss2,并将該節點内的ecap0: ecap@48304100改成ecap0:ecap@48304100,然後将該節點中的&ecap0_pins改成&ecap2_pins。
step3. 将ecap0_pins節點改名為ecap2_pins,然後将pinctrl-single,pins内的内容改為:0x19c mux_mode4。
最後修改後的dts相關部分如下:
backlight {
compatible = "pwm-backlight";
pwms = <&ecap2 0 50000 0>;
brightness-levels = <0 51 53 56 62 75 101 152 255>;
default-brightness-level = <8>;
&epwmss2 {
ecap2: ecap@48304100 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&ecap2_pins>;
ecap2_pins: backlight_pins {
pinctrl-single,pins = <
0x19c mux_mode4 /* mcasp0_ahclkr.ecap2_in_pwm2_out mode4 */
>;
這樣就完成了背光功能的dts配置。
(4)配置核心驅動
由于evm開發闆的代碼是使用atags方式啟動的,沒有配置pwm-backlight和基于ti lcd控制器的通用panel驅動,需要通過menuconfig開啟相應的配置項。通過dts中的compatible屬性可以找到pwm-backlight驅動是在drivers/video/backlight/pwm-bl.c中實作的,而panel驅動則是在drivers/gpu/drm/tilcdc/tilcdc_panel.c中實作的,閱讀相應目錄下的makefile和kconfig就可以确定出如何配置menuconfig。makefile和kconfig的分析過程很簡單,我就不多寫了,下面是通過menuconfig開啟相應功能的步驟。
step1. 執行menuconfig指令:
make arch=arm menuconfig
step2. 開啟通用pwm-backlight驅動和基于ti lcd控制器的通用panel驅動,配置内容如下:
graphics support --->
[*] pulse-width modulation (pwm) support --->
<*> ecap pwm support
<*> ehrpwm pwm support
-*- backlight & lcd device support --->
<*> generic pwm based backlight driver
graphics support --->
direct rendering manager --->
<*> direct rendering manager (xfree86 4.1.0 and higher dri support) --->
<*> drm support for ti lcdc display controller
(5)編譯dtb和核心
執行dtb編譯指令:
make arch=arm cross_compile=arm-linux-gnueabi- tq335x.dtb
執行核心編譯指令:
make arch=arm cross_compile=arm-linux-gnueabi- -j8
(6)用新核心啟動開發闆
将新編譯好的tq335x.dtb和zimage拷貝到sd卡的boot目錄下,然後用sd啟動開發闆到u-boot指令行模式,通過u-boot指令啟動核心(每次都這樣啟動會比較麻煩,可以通過設定u-boot的bootcmd環境變量并儲存來簡化此動作),啟動核心的指令與前一篇文章的指令是相同的:
load mmc 0 0x88000000 /boot/tq335x.dtb
load mmc 0 0x82000000 /boot/zimage
load mmc 0 0x88080000 /boot/ramdisk.img
bootz 0x82000000 0x88080000 0x88000000
這時,可以看到開發闆正常啟動并且能看到熟悉的linux小企鵝logo,至此,就完成了am335x的lcd驅動移植,實際上是不需要我們寫代碼的,但需要了解核心的組織方式和dts配置的方法。
(7)pinmux配置參數的确定方法
相信有些人看完這幾篇文章之後有個疑問,就是配置pinmux的時候offset是如何确定的。配置gpio管腳複用功能時經常用到pinctrl-single,pins = <offset, function>屬性,核心解析該屬性後根據offset和function配置對應的寄存器,是gpio管腳配置為指定的複用功能。
講offset的确定方法之前需要指出的是,ti的gpio控制與三星的晶片不同,三星的晶片管腳複用功能是放在gpio寄存器中的,而ti的晶片則有個專門的控制子產品叫control module,該子產品可以控制所有的gpio管腳功能複用;另外,與三星晶片的另外一個不同是ti的晶片分為技術參考手冊和資料手冊,技術參考手冊非常詳細的講述同family的晶片功能及使用方法,資料手冊則用來講述同family中不同晶片特有的屬性。是以,調試ti晶片時需要結合技術參考手冊和資料手冊,而配置gpio則需要閱讀技術手冊的gpio、control module兩章和資料手冊中相關的部分。
從am33xx.dtsi中可以看到pinmux的基位址是0x44e10800,我們先來看這個位址是怎麼來的。從技術參考手冊的記憶體映射表可以确定該位址位于l4_wkup段内,如下圖:
點選l4_wkup超連結,可以切換到l4_wkup的位址映射表,從該表中可以确定,該位址位于control module,如下圖:
點選control module的超連結,可以切換到control module的位址映射表,從該表中可以找到0x44e10800位址,實際上就是conf_gpmc_ad0控制寄存器的位址,也就是說,pinmux配置時的offset都基于這個位址的。
以pwm背光控制為例。該功能引腳是接在ecap2_in_pwm_out上的,實際上就是am335x的mcasp0_ahclkr管腳,該管腳的位址也可以在control module的位址映射表中找到,該管腳的位址是0x44e1099c(表中是基于control module的offset,這個值是計算之後的),是以,在pinmux中配置該引腳時使用的offset應該是0x19c,這樣就确定出了offset。
pinctrl-single,pins的第二項是function,用來指定gpio管腳是輸入還是輸出,目前處于哪種模式。輸入輸出很容易配置,但是am335x技術參考手冊中隻提到每個管腳有8中模式,即mode0~mode7,其中,mode0是主模式,但是沒有具體講每個引腳的每個mode是什麼功能,這時,就需要查閱am335x資料手冊了。在am335x資料手冊mcasp0_ahclkr的八種模式的含義,如下圖:
由于我們使用的是ecap2_in_pwm2_out功能,故使用mux_mode4。這就是backlight的pinmux配置時使用pinctrl-single,pins = <0x19c mux_mode4>的原因。
(8)效果展示
到這裡lcd的移植工作就算完成了,下面是tq335x驅動lcd後的效果圖:
(9)總結
使用dtb方式配置核心驅動一般需要以下幾個步驟:
step1. 設定pinmux,配置的gpio為相應的功能。
step2. 設定相應的節點,關聯對應的驅動。
step3. 檢查核心配置項,確定開啟對應的驅動選項。