S5pv210 HDMI 接口在 Linux 3.0.8 驅動框架解析 (By liukun321 咕唧咕唧)

文章來源 :http://blog.csdn.net/liukun321/article/details/18452663


作者:liukun321 咕唧咕唧

日期:2014.1.18

轉載請標明作者、出處:http://blog.csdn.net/liukun321/article/details/18452663

本文主要簡述S5pv210處理器的 HDMI 接口在 Linux 3.0.8 內核下的驅動框架。

        現在三星的主流處理器基本都支持HDMI,使用HDMI也有段時間了,卻一直不知道它是怎麼工作的,只知道linux和Android下都會有一個HDMI-service的用戶服務程序。然後底層會有HDMI驅動。知道HDMI 和framebuffer有點關係,卻不知道兩者是如何聯繫在一起的。從知道HDMI以來就覺得它神祕,出於好奇,決定揭開它的面紗一探真容。按照我的思路從下面四個方面並依照源碼簡單剖析一下Samsung S5pv210 處理器HDMI 在linux3.0.8下的驅動框架。

•      1.1 何爲HDMI,HDMI總線協議發展概況

•      1.2  HDMI驅動框架

•      1.3  從源碼,看HDMI設備驅動框架

•      1.4   從“疑問???”猜答案。(透過HDMI-service剖析HDMI與Framebuffer的關係。)

1.1  何爲HDMI,HDMI總線協議發展概況

         高清晰度多媒體接口(英文:HighDefinition Multimedia Interface,HDMI)是一種數字化視頻/音頻接口技術,是適合影像傳輸的專用型數字化接口,其可同時傳送音頻和影音信號,最高數據傳輸速度爲5Gbps。下面給出的是HDMI typeA型的公母頭,另外HDMI 還有typeB typeC 兩種類型的插頭。

  

       HDMI不僅可以滿足1080P的分辨率,還能支持DVDAudio等數字音頻格式,支持八聲道96kHz或立體聲192kHz數碼音頻傳送,可以傳送無壓縮音頻信號及視頻信號。 HDMI的設備具有“即插即用”的特點 。從下面的圖片我們看一下個版本HDMI的差別

 

   

在s5pv210處理器上的HDMI模塊是1.3版,Exyson4412上用的是1.4版。4412在hdmi上的優勢從上面的圖就一目瞭然了。從數據手冊上可以得到s5pv210處理器HDMI的基本參數:

 

 

1.2  HDMI驅動框架

       在介紹HDMI的驅動框架之前,首先需要了解一下HDCP,HPD,DDC 這幾個新名詞指的是什麼,否則直接深入源碼只會搞得暈頭轉向,然後就會覺得HDMI這玩意高深的不得了。其實它不怎麼深。。。^_^

•      HDCP: HDCP的全稱是High-bandwidthDigital Content Protection,也就是“高帶寬數字內容保護”。

•      DDC: HDCP數據祕鑰在CPU和顯示設備間的交換以及EDID(EDID中包含有關顯示器及其性能的參數)要通過hdmi 接口的兩個DDC(IIC總線)引腳實現.(實質是實現一個IIC設備驅動)

•      HDP:Hot PlugDetection,在HDMI的一對聯接中,爲熱插拔的實現而設計的。簡單地說,當發送端接入接受端時,接受端會迴應HPD信號給發送端,進而發送端會啓動DDC通道,而讀取接受端EDID的信息,然後進行HDCP的交互,如果雙方認證成功,則視頻、音頻正常工作,否則聯接失敗,不同系統會有不同的處理。

     HDCP,HPD,DDC 這幾個新名詞清楚了,那就得想想它們作爲HDMI的一個組件(這個詞不清楚用的是否恰當)之間有什麼樣的聯繫呢?其實上面說的已經差不多了,我再簡單總結下:

     HDCP起到一個數字內容保護的作用,它的祕鑰交換需要用到IIC總線,也就是HDMI的DDC通道。另外HDMI還需要從顯示設備獲得顯示相關參數(EDID),比如分辨率等顯示信息。這個信息也是通過IIC總線交互的,走的也是DDC通道。HPD就不用多說了,HDMI熱插拔後的“工作”全靠它了。Linux驅動需要分別實現這幾個組件的驅動,這幾個組件的驅動相互配合共支撐實現了HDMI 驅動。下面就先把HDMI框架畫出來。


         這裏還需要介紹一下CEC:可以簡單理解 當您有很多HDMI設備通過HDMI線,切換器或者分配器連在一起的時候,如果所有的HDMI產品都支持CEC功能,那麼可以利用其中一臺的遙控器可以去控制其他的設備. 這就是CEC功能。210也提供了HDMI cec的驅動源碼,並且生成了供給用戶空間操作的設備文件(它是作爲混雜設備被註冊進內核),從上面的框圖也可以看到,CEC驅動的實現不同於HDCP、HPD、DDC 等組件的驅動向內核空間提供了函數接口。CEC驅動中僅實現了file_operation操作方法,供給用戶對設備文件操作時調用。並沒有對內核空間暴露函數接口。

         再簡單說明下框架:在linux 3.0.8中HDMI作爲TV_OUT的一部分,TV_OUT驅動註冊時,HDMI作爲TV_OUT的一個子系統被初始化。【當TV_OUT的探針函數(static int __devinit s5p_tv_probe(struct platform_device *pdev))被執行時,會調用HDMI相關初始化函數s5p_hdmi_probe(pdev,3, 4);】。並且同時會註冊一個符合V4L2標準的設備,因此用戶空間對HDMI設備(video14)的基本操作如設置分辨等操作符合V4L2標準操作(這個在後面還會根據源碼深入分析)。而CEC HDCP DDC HPD作爲HDMI的組件,他們的驅動實現即爲HDMI驅動的實現提供函數接口(HDCP DDC HPD 這三個組件的驅動會互相暴露函數調用),也爲用戶空間提供了操作這個組件的方法(HPD CEC這兩個組件的驅動向用戶空間提供了操作方法)。

         通過上面的框圖可以看到,我們在用戶空間可以看到的跟HDMI相關的設備文件只有三個,分別是CEC HPD video14 這三個設備文件,根據驅動中實現的方法應用程序可以通過這三個設備文件分別是實現HDMI CEC功能操作、讀取熱插拔HDMI設備狀態、對HDMI設備操作。這三個設備文件是如何生成的,他們提供了哪些操作方法呢?看下面的分析----------

 

1.3  透過源碼看HDMI設備驅動框架的實現

          HDMI的這幾個組件都有自己的驅動源文件,下面就分開看看各組件驅動的實現及其在HDMI主體驅動中的作用

HDMI DDC 驅動:

         

先來看看HDMI DDC驅動,DDC驅動實際上實現了一個標準IIC設備的驅動。

DDC設備註冊:

DDC設備結構,在板級初始化時被註冊進內核mach-XXX210.c(我用的是tiny210 mach-mini210.c)


這是DDC設備結構體,其中包含了DDC設備IIC總線上的地址信息。在mini210_machine_init(void) 函數中會調用:

i2c_register_board_info(1,mini210_i2c_devs1,ARRAY_SIZE(mini210_i2c_devs1));函數將這個結構註冊進內核。如下圖所示:

再看一下DDC驅動註冊:

           這是DDC驅動的結構體。在內核啓動後start_kernel  -->rest_init() -->kernel_init() --> do_basic_setup()  -->do_initcalls()  執行到do_initcalls函數時所有帶有__init標示的函數被順序執行這裏ddc_init函數就被執行了,將上面的驅動結構註冊進內核如下圖:

   若IIC總線上設備、驅動匹配,則ddc_probe函數被執行。ddc_probe函數內容如下:

     ddc_probe函數被執行後會獲得IIC設備資源,主要是IIC設備地址信息。

        DDC驅動中實現了兩個方法,這兩個方法不暴露給用戶,暫且稱爲“內核API”(這種說法不太準確,爲了方便後面暫且這麼叫).驅動將這兩個方法,提供給HDMI 的HDCP驅動調用(HDCP 祕鑰的交換需要用到DDC組件)。這兩個方法的實現如下:


DDC驅動內容大致就這麼多

 

 HDMI HDCP 驅動:

下面瞭解一下HDCP驅動:

        HDCP驅動完全沒有給用戶空間提供操作接口,對用戶空間來說感覺不到它的存在,但是驅動提供了“內核API”供HDMI 驅動及其它組件調用。對外暴露的函數列表如下:

static ints5p_hdcp_is_reset(void) //函數功能:判斷HDCP的自旋鎖是否已經被獲取如果被獲取返回1,否則返回0.函數未被調用。

static bools5p_set_hpd_detection(bool detection, bool hdcp_enabled,struct i2c_client*client)// 函數功能:檢測HPD引腳狀態,函數未被調用。

int s5p_hdcp_init(void)//函數功能:初始化HDCP

bool s5p_start_hdcp(void)// 函數功能:開啓HDCP功能,並從顯示設備獲得祕鑰。

bool s5p_stop_hdcp(void)// 函數功能:關閉HDCP功能

ints5p_hdcp_encrypt_stop(bool on)// 函數功能:當HDMI接口拔下時,會執行這個函數,停止HDCP加密

int s5p_hdmi_set_dvi(boolen)// 函數功能:設置開啓/關閉DVI 標誌

voids5p_hdmi_set_audio(bool en)// 函數功能:設置開啓/關閉 PCM流無損音頻輸出 標誌

ints5p_hdmi_audio_enable(bool en)// 函數功能:開啓音頻輸出

ints5p_hdmi_set_mute(bool en) // 函數功能:設置聲音圖像消隱 開啓/關閉 標誌

ints5p_hdmi_get_mute(void) // 函數功能:獲得聲音圖像消隱 開啓/關閉 標誌狀態

voids5p_hdmi_mute_en(bool en) // 函數功能:開啓聲音圖像消隱

 

        順便提一下什麼是聲音圖像消隱:簡單來說就是顯示設備的聲音至於靜音狀態、圖像至於黑屏狀態。比如HDMI輸出設備在切換分辨率、Color Space、開關機等操作時,顯示設備可能會看到一些過度花屏的現象,所以,HDMI輸出設備在進行相應操作之前,發送給顯示設備一個AVMute信號,讓顯示設備至於黑屏靜音狀態,等待HDMI輸出設備切換好後,再發送一個Clear AVMute信號,讓顯示設備再開機,這樣,切換過程中的花屏現象就會被屏蔽掉。

 

HDCP驅動大致就提供了這些接口函數,供HDMI驅動的其它組件調用。

 

HDMI HPD 驅動:

然後再介紹一下HPD驅動:

         HPD驅動使用了Platform&misc框架。 設備結構註冊到內核,驅動結構體註冊到內核,設備驅動匹配後,HPD 的探針函數中(probe)獲得設備資源,並註冊一個混雜設備,這時會在根文件系統生成設備文件HPD,用戶可以通過驅動所支持的方法,操作設備文件,從而獲得HDMI HPD引腳線的狀態。這段文字用源碼的形式展現如下:

Mach-mini210.c文件中,HPD設備結構的定義如下

作爲板級平臺設備,上面的結構包含在mini210_devices數組中

系統平臺設備初始化(mini210_machine_init(void) ----àplatform_add_devices)時,將設備結構s5p_device_hpd註冊進內核。

 

下面的代碼在函數 s5p_hpd_init 中將驅動結構 s5p_hpd_driver 註冊進內核


當platform的設備和驅動匹配後執行probe探針函數

探針函數s5p_hpd_probe 中註冊將HPD註冊爲一個混雜設備,設備結構體如下

         可以看到這個驅動中的file_operations結構實現了 s5p_hpd_open、s5p_hpd_release 、s5p_hpd_read 、s5p_hpd_poll 這幾個方法。用戶可以通過read 系統調用實現讀取HPD引腳的狀態。

另外HPD驅動中還有三個函數(方法):

int s5p_hpd_get_state(void)

int s5p_hpd_set_hdmiint(void)

int s5p_hpd_set_eint(void)

這三個操作方法,作爲Kernel API  供給HDMI驅動核心調用,分別用於獲取當前HDMI接口狀態、上電初始化HDMI HPD  、及上電初始化HPD引腳中斷。

 

HDMI 主設備驅動

下面就要進入HDMI驅動最精彩的部分了,HDMI 設備的註冊:HDMI作爲TV_OUT的一部分,設備資源包含在TV_OUT設備資源結構中如下圖數組中下標爲3、4的元素:

 

下面是TV_OUT的設備結構體:

它作爲板級平臺設備,被下面的數組包含


 

在mini210_machine_init函數中 的 platform函數被調用時註冊進內核



下面是TV_OUT的驅動結構體


在s5p_tv_init函數中 s5p_tv_driver 被註冊進內核

當platform的設備和驅動匹配時執行探針函數(probe)s5p_tv_probe

         這個probe函數中與HDMI相關的s5p_hdmi_probe 函數被調用,完成HDMI設備的初始化。

緊接着,在probe函數中,下面紅框內調用video_device_register 函數,將HDMI設備註冊,

函數會獲得s5p_tvout這個結構,

        並會被註冊爲遵循V4L2框架的 video設備,對HDMI的操作函數嵌入到v4l2框架。,然後會在根文件生成名爲 video14 的設備文件(.minor = TVOUT_MINOR_TVOUT, 這個元素中TVOUT_MINOR_TVOUT宏展開爲14 )。

而對video14(HDMI)設備的操作函數最終通過V4L2框架封裝暴露給用戶空間,實現的操作方法如下:

符合V4L2框架的ioctl操作

到此爲止我們已經可以通過/dev/video14  設備文件,按照V4L2規範對HDMI進行操作了。

 

HDMI CEC驅動 暫略後面會補上

1.4疑問???

到現在爲止,我們應該還有一個疑問,用戶空間是如何使用HDMI設備的,由此可以引出四個問題:

•      在用戶空間如何配置HDMI?

•      HDMI顯示數據從哪來?

•      HDMI顯示和Framebuffer有何關聯?

從android的HDMI-service 我們可以看到,在Service中打開HDMI 設備:(/device/samsung/proprietary/libhdmi/SecHdmi.cpp)


          並且會在Overlay的初始化過程將HDMI顯示與Framebuffer關聯起來。在overlay.cpp 中會在系統啓動時對HDMI進行初始化,將幀緩衝內存映射到HDMI 顯示緩衝區中。源碼中的buffer指針指向幀緩衝區

       經過上述方法,實現了幀緩衝區向HDMI接口的映射。我們在應用程序中,只需要向幀緩衝區中寫入圖像數據就會通過HDMI輸出到顯示設備上(HDMI-service正常工作做的前提下,HDMI-service在系統啓動後被啓動,用來初始化HDMI基本參數,如分辨率等)。

映射完成後 framebuffer與HDMI 的關係如下圖:

         至此HDMI驅動框架介紹完畢。由於網上基本搜不到210 HDMI的linux驅動相關信息,以上內容都是通過讀源碼分析總結的,可能會有一些認識錯誤,還請大家在閱讀後及時指正,謝謝。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章