Linux驅動基礎:device tree

Bootloader設置

msm平臺爲例,在bootloader代碼中會根據當前ddr開始的地址,按照一定的offset定義了kernel開始的地址,ramdisk開始地址以及TAG開始的地址。其中kernel代碼開始的地址和ramdisk的地址自不必說,這兩個不對的話再加載完kernel代碼之後跳到kernel代碼都會有問題,或者ramdisk的mount都會有問題。Device Tree也一樣,這裏定義的ABOOT_FORCE_TAGS_ADDR偏移量也要和打包boot.img的時候,dt.img的偏移量保持一致,不然也是找不到dt.img進行device tree內容的初始化的。

//bootloader裏邊定義瞭如下內容
#define DDR_START                   get_ddr_start()
#define ABOOT_FORCE_KERNEL_ADDR     DDR_START + 0x8000
#define ABOOT_FORCE_KERNEL64_ADDR   DDR_START + 0x80000
#define ABOOT_FORCE_RAMDISK_ADDR    DDR_START + 0x2000000
#define ABOOT_FORCE_TAGS_ADDR       DDR_START + 0x1E00000

device tree相關的ABOOT_FORCE_TAGS_ADDR,在DDR_START地址爲0x80000000的時候加上ABOOT_FORCE_TAGS_ADDR的值爲0x81E00000。這個值kernel會保存在__atags_pointer變量中,用來在內核尋找device tree相關的內容。

setup_arch()->setup_machine_fdt(__atags_pointer);

在boot.img編譯的時候正確指定devicetree的偏移量,才能在內核運行階段找到相應的device tree,並初始化device tree的節點等。當然偏移量和上面的__atags_pointer一樣。
下面來看一下在boot.img打包的命令,這裏可以看到BOARD_KERNEL_TAGS_OFFSET這個值和上面bootloader裏邊定義的偏移量是一致的。

$MKBOOTIMGTOOL --kernel $KERNEL_ZIMG \ 
--ramdisk $PRODUCT_OUT/ramdisk.img \
--output $PRODUCT_OUT/boot.img \
--cmdline "$BOARD_KERNEL_CMDLINE" \
--base $BOARD_KERNEL_BASE \
--pagesize $BOARD_KERNEL_PAGESIZE \
--ramdisk_offset $BOARD_RAMDISK_OFFSET \
--tags_offset $BOARD_KERNEL_TAGS_OFFSET \
--dt $INSTALLED_DTIMAGE_TARGET"

KERNEL_ZIMG=$BUILD_KERNEL_OUT_DIR/arch/arm/boot/zImage
BOARD_KERNEL_BASE=0x80000000
BOARD_KERNEL_PAGESIZE=2048 
BOARD_KERNEL_TAGS_OFFSET=0x01E00000
BOARD_RAMDISK_OFFSET=0x02000000
BOARD_KERNEL_CMDLINE="console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 androidboot.bootdevice=7824900.sdhci"

#BOARD_KERNEL_CMDLINE="console=ttyHSL0,115200,n8 androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x37 ehci-hcd.park=3"

#BOARD_KERNEL_CMDLINE="console=ttyHSL0,115200,n8 androidboot.hardware=qcom androidboot.bootdevice=soc.0/7824900.sdhci user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 video=vfb:640x400,bpp=32,memsize=3072000 earlyprintk"
INSTALLED_DTIMAGE_TARGET=${PRODUCT_OUT}/dt.img
DTBTOOL=$BUILD_KERNEL_DIR/tools/dtbTool

ABOOT_FORCE_KERNEL_ADDR開始的地址偏移量是0x8000,就是說kernel code開始的地址,
也就是和_text的值一樣是0x8000。
0x8000以下放了一些東西,比如偏移0x4000的地方放了swapper_pg_dir(page table)。
ABOOT_FORCE_TAGS_ADDR這個地址通過__atags_pointer這個值被傳到kernel,來進行device tree的讀取並初始化platform_device等操作。
也就是說__atags_pointer等於ABOOT_FORCE_TAGS_ADDR的值,也等於BOARD_KERNEL_TAGS_OFFSET這個值。還有__atags_pointer這個值在內核dump文件裏邊是找不到的,因爲這個值定義成了
unsigned int __atags_pointer __initdata; //這裏帶了__initdata!!,後面會被釋放掉
初始化用完之後都被釋放掉了。

內核中的初始化

device tree的初始化開始的函數是:

setup_machine_fdt(__atags_pointer) =>
const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{}

dts文件中定義的名字和board-xx.c文件中定義的DT_MACHINE_START名字需要對應。
這裏寫圖片描述

這裏寫圖片描述

Device Tree的優點

使能了device tree(menuconfig → boot options → flattened device tree)之後,可以不用添加很多board-xxx.c文件去定義platform device。device tree會在machine_init()的時候初始化所有的platform device。
Platform device相關的device tree:
- of_platform_populate()會根據在&soc{}裏邊定義的所有內容去初始化所有的platform device
- 在每個node裏邊必須包含compatible項,這樣才能在platform driver初始化的時候找到相應的platform device。
- For creating platform devices for sub-nodes, provide a list
of all root nodes (second parameter)????

Platform驅動裏的用法

需要添加device tree的內容以定義platform device,然後在platform driver裏邊讀出來的步驟如下:
1. 添加一個node到device tree文件中
這裏寫圖片描述
2. 在platform驅動文件中添加如下內容,讓驅動可以找到上面定義的platform device的內容
這裏寫圖片描述
3. 使用of_property_read_u32()等接口讀取device tree節點裏的內容
這裏寫圖片描述

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