針對重復的代碼問題,如果不同的SOC使用了相同的IP block(例如I2C controller),那么這個driver的code要從各個arch/arm/mach-xxx中獨立出來,變成一個通用的模塊供各個SOC specific的模塊使用。移動到哪個目錄呢?對於I2C或者USB OTG而言,這些HW block的驅動當然應該移動到kernel/drivers目錄。因為,對於這些外設,可能是in-chip,也可能是off-chip的,但是對於軟件而言,它們是沒有差別的(或者說好的軟件抽象應該掩蓋底層硬件的不同)。對於那些system level的code呢?例如clock control、interrupt control。其實這些也不是ARM-specific,應該屬於linux kernel的核心代碼,應該放到linux/kernel目錄下,屬於core-Linux-kernel frameworks。當然對於ARM平台,也需要保存一些和framework交互的code,這些code叫做ARM SoC core architecture code。OK,總結一下:
1、ARM的核心代碼仍然保存在arch/arm目錄下 2、ARM SoC core architecture code保存在arch/arm目錄下 3、ARM SOC的周邊外設模塊的驅動保存在drivers目錄下 4、ARM SOC的特定代碼在arch/arm/mach-xxx目錄下 5、ARM SOC board specific的代碼被移除,由Device Tree機制來負責傳遞硬件拓撲和硬件資源信息。
本質上,Device Tree改變了原來用hardcode方式將HW 配置信息嵌入到內核代碼的方法,改用bootloader傳遞一個DB的形式。對於基於ARM CPU的嵌入式系統,我們習慣於針對每一個platform進行內核的編譯。但是隨着ARM在消費類電子上的廣泛應用(甚至桌面系統、服務器系統),我們期望ARM能夠象X86那樣用一個kernel image來支持多個platform。在這種情況下,如果我們認為kernel是一個black box,那么其輸入參數應該包括:
1、識別platform的信息 2、runtime的配置參數 3、設備的拓撲結構以及特性
對於嵌入式系統,在系統啟動階段,bootloader會加載內核並將控制權轉交給內核,此外,還需要把上述的三個參數信息傳遞給kernel,以便kernel可以有較大的靈活性。在linux kernel中,Device Tree的設計目標就是如此。
針對重復的代碼問題,如果不同的SOC使用了相同的IP block(例如I2C controller),這些都會集中統一管理,放在driver/目錄下。
就比如說S5PV210的Display controller和Exynos 4412的Display controller使用的是同一個IP block,那么關於這個IP block,的通用的代碼應該是統一組織放在driver/目錄下,他們兩個IP block,針對不同的SOC,不同的可能是這個控制器在SOC的起始地址可能不同,當然這個就比較好解決了,這個也是Device tree應該且必要做的事情。
例如在s5pv210中,起始地址是從0xf8000000開始的
而exyson-4412中,起始地址則是在0x11c00000
這樣如果一個芯片廠家如果使用相同IP block的Display controller,將來就可以不用寫相關的驅動了,而只需要在設備樹文件中描述自己SOC中對這個IP block的寄存器地址,時鍾,中斷信息的就可以了。
當然,對於像USB中的ohci,ehci或者xhci更是如此,畢竟這些控制器,都是USB協議規定的,一般來說基本上大多數廠家寄存器的排布地址都會是一樣的。
所以對於SOC廠家,都只需要在設備樹中指定寄存器起始地址,中斷,時鍾信息等就可以了,完全不用自己在向之前一樣要根據一塊單板或一款SOC就要寫一個控制器寫一個類似的驅動程序。