結合裝置資訊集合,探究裝置和驅動是如何繫結的
本文結合裝置資訊集合的詳細講解來認識一下裝置和驅動是如何繫結的。所謂裝置資訊集合,就是根據不同的外設尋找各自的外設資訊,我們知道一個完整的開發板有 CPU 和各種控制器(如 I2C 控制器、SPI 控制器、DMA 控制器等),CPU和控制器可以統稱為 SOC,除此之外還有各種外設 IP,如 LCD、HDMI、SD、CAMERA 等,如下圖:
我們看到一個開發板上有很多的裝置,這些裝置是如何一層一層展開的呢?裝置和驅動又是如何繫結的呢?我們帶著這些疑問進入本節的主題。
各級裝置的展開
核心啟動的時候是一層一層展開地去尋找裝置,裝置樹之所以叫裝置樹也是因為裝置在核心中的結構就像樹一樣,從根部一層一層的向外展開,為了更形象的理解來看一張圖:
大的圓圈中就是我們常說的 soc,裡面包括 CPU 和各種控制器 A、B、I2C、SPI,soc 外面接了外設 E 和 F。IP 外設有具體的匯流排,如 I2C 匯流排、SPI 匯流排,對應的 I2C 裝置和 SPI 裝置就掛在各自的總線上,但是在 soc 內部只有系統匯流排,是沒有具體匯流排的。
第一節中講了匯流排、裝置和驅動模型的原理,即任何驅動都是透過對應的匯流排和裝置發生聯絡的,故雖然 soc 內部沒有具體的匯流排,但是核心透過 platform 這條虛擬匯流排,把控制器一個一個找到,一樣遵循了核心高內聚、低耦合的設計理念。下面我們按照 platform 裝置、i2c 裝置、spi 裝置的順序探究裝置是如何一層一層展開的。
展開 platform 裝置
上圖中可以看到紅色字型標註的 simple-bus,這些就是連線各類控制器的匯流排,在核心裡即為 platform 匯流排,掛載的裝置為 platform 裝置。下面看下 platform 裝置是如何展開的。
還記得上一節講到在核心初始化的時候有一個叫做 init_machine() 的回撥函式嗎?如果你在板級檔案裡註冊了這個函式,那麼在系統啟動的時候這個函式會被呼叫,如果沒有定義,則會透過呼叫 of_platform_populate() 來展開掛在“simple-bus”下的裝置,如圖(分別位於 kernel/arch/arm/kernel/setup。c,kernel/drivers/of/platform。c):
這樣就把 simple-bus 下面的節點一個一個的展開為 platform 裝置。
展開 i2c 裝置
有經驗的小夥伴知道在寫 i2c 控制器的時候肯定會呼叫 i2c_register_adapter() 函式,該函式的實現如下(kernel/drivers/i2c/i2c-core。c):
註冊函式的最後有一個函式 of_i2c_register_devices(adap),實現如下:
of_i2c_register_devices()函式中會遍歷控制器下的節點,然後透過of_i2c_register_device()函式把 i2c 控制器下的設備註冊進去。
展開 spi 裝置
spi 裝置的註冊和 i2c 裝置一樣,在 spi 控制器下遍歷 spi 節點下的裝置,然後透過相應的註冊函式進行註冊,只是和 i2c 註冊的 api 介面不一樣,下面看一下具體的程式碼(kernel/drivers/spi/spi。c):
當透過 spi_register_master 註冊 spi 控制器的時候會透過 of_register_spi_devices 來遍歷 spi 匯流排下的裝置,從而註冊。這樣就完成了spi裝置的註冊。
【文章福利
】小編推薦自己的Linux核心技術交流群:【
865977150
】整理了一些個人覺得比較好的學習書籍、影片資料共享在群檔案裡面,有需要的可以自行新增哦!!!
核心學習網站:
各級裝置的展開
學到這裡相信應該瞭解裝置的硬體資訊是從裝置樹裡獲取的,如暫存器地址、中斷號、時鐘等等。接下來我們一起看下這些資訊在裝置樹裡是怎麼記錄的,為下一節動手定製開發板做好準備。
1。reg 暫存器
我們先看裝置樹裡的 soc 描述資訊,紅色標註的代表著暫存器地址用幾個資料量來表述,綠色標註的代表著暫存器空間大小用幾個資料量來表述。圖中的含義是中斷控制器的基地址是 0xfec00000,空間大小是 0x1000。如果 address-cells 的值是 2 的話表示需要兩個數量級來表示基地址,比如暫存器是 64 位的話就需要兩個數量級來表示,每個代表著 32 位的數。
2。ranges 取值範圍
ranges 代表了 local 地址向 parent 地址的轉換,如果 ranges 為空的話代表著與 cpu 是 1:1 的對映關係,如果沒有 range 的話表示不是記憶體區域。