8/11/2015

Device Tree 기본설명 및 문법, 부팅방법 (AM437x,AM335x)

1. Device Tree 의 기본구성

Device Tree에서 사용되어지는 기본 용어들을 알아두자.
  • DTB : Deivce Tree Blob (DTC에 의해  DTS를 Compile하면 생성되는 파일) 
  • DTC:  Device Tree Compiler 
  • DTS :  Device Tree Syntax  
  • DTSI : Device Tree Syntax Include 

개발자는  DTS와 DTSI를 이용하여 Driver 설정 (HW 설정)구성 한 후 이를 DTC로 Compile 후 이를  DTB 형태로 사용하면 된다 

DTB를 적용하기 위해서는 Kernel에서도 .config에서도 적용이 되게 설정을 해야한다. 

최근에 사이트를 방문하니, Spec이 만들어져 있어 아래 부분을 링크

  http://www.devicetree.org/specifications/


1.1 DTS(Device Tree Source) 기본문법 

Device Tree는 현재 문법이 조금씩 다른것 같으며, 표준화가 진행이 되는 것 같으며,
이를 아래의 사이트에서 Version에 맞게 사용해야 할 것 같다.
하지만 각 Chip Vendor마다 조금씩 다르므로 각각의 Datasheet를 보고 파악을하는 것이 나을 것 같다.
다만 기본문법만  아래의 링크들을 보고 알아두자

  • Device Tree Spec 
 현재 이곳에서 인터넷에서 기재되고, 이곳에서 Device Tree를 관리한다.
  https://www.devicetree.org

  • Ubuntu 에서 ARM Device 를 위하여 Device Tree를 사용 할 경우 
  https://wiki.ubuntu.com/Kernel/Dev/ARMDeviceTrees?action=show&redirect=KernelTeam%2FARMDeviceTrees

  • Device Tree 사용법 ( Spec 및 관련문서 중요)
  https://www.kernel.org/doc/Documentation/devicetree/usage-model.txt
  http://www.devicetree.org/Device_Tree_Usage
  http://www.devicetree.org/specifications/

  • 현재 Device Tree의 적용되는 예
  https://en.wikipedia.org/wiki/Device_tree
  http://omappedia.org/wiki/Device_Tree     (TI)

  • Device Tree 사용법 소개
  http://elinux.org/Device_Tree
  http://elinux.org/Linux_Drivers_Device_Tree_Guide


1.2 DTS/DTSI(Device Tree Source)  위치확인  

이제 본인의 Kernel로 가서 아래와 같이 DTS의 위치를 확인하고, ARM64 or ARM32를 본인 CPU로 확인 후, 이제 본격적으로 자신의 DTS를 찾아보자.
빌드를 하면 본인의 dtb가 생성되므로 이 기준으로 찾아도 좋다

$ find . -name dts  // DTS 관련부분 전부 검색  
./arch/xtensa/boot/dts
./arch/arc/boot/dts
./arch/arm/boot/dts
./arch/arm64/boot/dts
./arch/nios2/boot/dts
./arch/powerpc/boot/dts
./arch/c6x/boot/dts
./arch/metag/boot/dts
./arch/mips/boot/dts
./arch/openrisc/boot/dts
./arch/cris/boot/dts
./arch/h8300/boot/dts
./arch/microblaze/boot/dts

  • DTS 와 DTSI 
Kernel의 arch/x/boot/dts에  DTS와 DTSI파일들이 존재하며, 이 파일로 설정이 가능하다.
DTS는 C언어 처럼 include가 가능하여, DTSI를 사용한다.

    arch/arm/boot/dts/
    arch/powerpc/boot/dts/


1.3 DTC(Device Tree Compiler) 위치확인 

DTC는 kernel에서 빌드되며 아래와 같이 Version이 존재하고, 관련 Source도 Kernel 내부에 존재한다.
  1. DTC의 빌드      : Kernel Config의  CONFIG_DTC=y 추가 
  2. DTC 의 Source :  ./script/dtc 


$ find . -name dtc   // Complier 확인 
./scripts/dtc        // dtc parser and lexer 및 기타소스 확인   
./scripts/dtc/dtc    // dtc bin 


$ cd ./scripts/dtc 
$ ./dtc -v
Version: DTC 1.4.1-g9d3649bd   // DTC Version 확인 


2. Device Tree를 이용한 Kernel Boot

우선 기존의 Kernel Image Boot 와 과 Device Tree를 이용한 Kernel Image을 비교하고, Device Tree를 이용할 경우 DTB 전달방법을 알아보자.


2.1 Kernel Image 비교

Bootloadr에서 DTB(Device Tree Blob)파일을 load 한 후 이를 Kernel로 넘겨주고, 이는 기존의 Kernel의 board-*.c를 대체하고 기존에 사용하던 
platform_device_registraition 방식을 제거를 하고 이 DTB를 사용하여 동적으로 변경한다.


  • uImage의  Old style 과 New Style 비교 

 
http://www.elinux.org/images/a/ad/Arm-soc-checklist.pdf


  • 3가지 모델로 제안하여 DTB도 두가지방식 
  1. OLD Style: 기존방식 MACHINE IDMACHINE_START/END 사용 
  2. 1stNew Style: DTB와 uImage 분리되며, U-BOOT에서 uImage 와 DTB 주소 전달
  3. 2ndNew Style: uImage 와 DTB File을 포함  (Uboot에서 DTB를 전달필요없음)



  • Kernel Image는 uImage or zImage로도 가능
  1. vmlinux : linux kernel의 ELF format으로 실행가능한 kernel이며 기본적인 kernel 
  2. image  : vmlinux 기반에서 objcopy에서 -O binary -R .comment -S 
  3. zImage : vmlinux기반에서 linkscript 기반으로 piggy 및 head 와 gzip 등을 포함한 Kernel Image 
  4. uImage : zImage 기반으로 작성되며 uboot용으로 변경 


$ cd board-support/linux*  //kernel source 이동
$ cd arch/arm/boot
$ ls -a
.Image.cmd  .gitignore  .zImage.cmd  Image  Makefile  bootp  compressed  dts  install.sh  zImage

$ cat .Image.cmd   // Image 만들어지는 방법 
cmd_arch/arm/boot/Image := /home/jhlee/am437x/works/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-objcopy -O binary -R .comment -S  vmlinux arch/arm/boot/Image

$ cat .zImage.cmd  // zImage 만들어지는 방법 
cmd_arch/arm/boot/zImage := /home/jhlee/am437x/works/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-objcopy -O binary -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage

$ cd compressed
$ ls 
Makefile        big-endian.S  decompress.o  fdt_ro.o   head-sa1100.S    head.o       libfdt.h           misc.o          piggy.lz4.S     sdhi-shmobile.c  vmlinux.lds
ashldi3.S       bswapsdi2.S   fdt.c         fdt_rw.c   head-sharpsl.S   hyp-stub.S   libfdt_env.h       mmcif-sh7372.c  piggy.lzma.S    sdhi-shmobile.h  vmlinux.lds.in
ashldi3.o       bswapsdi2.o   fdt.h         fdt_rw.o   head-shmobile.S  hyp-stub.o   libfdt_internal.h  piggy.gzip      piggy.lzo.S     string.c
atags_to_fdt.c  debug.S       fdt.o         fdt_wip.c  head-xscale.S    lib1funcs.S  ll_char_wr.S       piggy.gzip.S    piggy.xzkern.S  string.o
atags_to_fdt.o  decompress.c  fdt_ro.c      fdt_wip.o  head.S           lib1funcs.o  misc.c             piggy.gzip.o    sdhi-sh7372.c   vmlinux


  • Kernel Image 구조 
  https://en.wikipedia.org/wiki/Vmlinux
  https://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/kernel-image-file-structure.html


  • AM437x EVM Kernel Config 설정 

$ vi .config  //AM437x Kernel config  
....
CONFIG_DTC=y
CONFIG_OF=y

#
# Device Tree and Open Firmware support
#
CONFIG_PROC_DEVICETREE=y
# CONFIG_OF_SELFTEST is not set
CONFIG_OF_FLATTREE=y
CONFIG_OF_EARLY_FLATTREE=y
.....

#
# Boot options
#
CONFIG_USE_OF=y
CONFIG_ATAGS=y
# CONFIG_DEPRECATED_PARAM_STRUCT is not set
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
CONFIG_CMDLINE_FROM_BOOTLOADER=y
# CONFIG_CMDLINE_EXTEND is not set
# CONFIG_CMDLINE_FORCE is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y
# CONFIG_CRASH_DUMP is not set
CONFIG_AUTO_ZRELADDR=y


Kernel의 설정에 따라 전달방식은 두가지 설정
(CONFIG_ARM_APPENDED_DTB 와 ATAG)


  • 아래의 ARM 파트와 DT 전달방식을 확인
  아래의사이트에 너무자세하게 나와있다.
  http://lxr.free-electrons.com/source/Documentation/devicetree/booting-without-of.txt

  • DTC 생성 
    CONFIG_DTC=y 에 의해 ./script/dtc/dtc가 생성이 된다.

  • DTB Data를 전달하는 두가지 방식 
  1. uImage와 DTB를 합쳐서 설정하는 방식  
  2. DTB 와 uImage를 분리하며, uboot에서 이를 전달하는 방식 (3.1/2/3 설명 )  

2.2 Kernel설정 (1st New Style)

DTB와 Kernel이 분리된 경우 사용하며, 문서에도 보면 이부분을 선호하며, UBOOT에서 동적으로 맘대로 DTB만 변경만 하면 되기 때문에 편할 것으로 보인다.
2nd New Style 부분은 uImage와 DTB를 합치는 것이며 별도의 Kernel 설정이 필요하며 이부분은 생략

  • ATAGS 사용 및 소개 
UBOOT에서 Kernel에게 Taglist 를 전달해주는 개념이며, 이 Taglist에 받아 Kernel이 이를 사용한다.
Device Tree가 나오기전의 개념이며, 이것 단독으로 Device Tree를 사용할 수 없지만,이를 Device Tree에 적용하여 사용이 가능하다.


  • Kernel Config 설정
  1. CONFIG_ATAGS      //ATAGS 사용하여 TAG LIST로 받음 
  2. CONFIG_ARM_ATAG_DTB_COMPAT // TAG LIST에서 DTB를 받아 호환 
  3. CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER // TAG LIST DTB 포함 
  4. CONFIG_ARM_APPENDED_DTB // DTB가 Kernel Image에 포함
  5. CONFIG_ATAGS_PROC // ATGAS PROC 정보 


2.3 UBOOT의 Kernel DTB 전달과정 (1st New Style)


 A. UBOOT에서 KERNEL 의 ATAGS의 TAGLIST 전달방식

아래와 같이 ATAGS 기능 사용할 경우 전달 방식이 변경이 된다.r2에 Taglist를 전달해준다.
ATAGS 방식은 기존부터 존재하던 방식으로 ATAGS에 다양한 정보를 넣어 전달가능.
http://events.linuxfoundation.org/sites/events/files/slides/petazzoni-device-tree-dummies.pdf
       
B. 상위 ATAGS의 TAGLIST 미사용하고 DTB 주소설정

DTB를 전달할 경우, 아래와 같이 R2에 DTB의 주소를 넣어서 전달

http://events.linuxfoundation.org/sites/events/files/slides/petazzoni-device-tree-dummies.pdf


3. UBOOT의 Kernel DTB 전달방식 (1st New Style)

  • UBOOT 의 Kernel 의 DTB 전달 방식  (ATAG 사용)
bootm 은 uImage를 사용할이며, bootz는 zImage 사용할때이다.
앞에 kernel의 이미지를 address 주고  "-" 함께  dtb file address 주소를 준다.

$ bootm ${loadaddr} - ${fdtaddr} 
$ bootz ${loadaddr} - ${fdtaddr}


  • ATAGS 미사용과 Device Tree Mapping된 경우 전달형태

 CPU register contents
       r0 = 0
       r1 = Linux SOC family DT machine number  (Machine ID)
            (as defined in the ARM Linux machine database). 
            Unlike legacy ATAG booting, there is one unique ID is per SOC family not per machine.
       r2 = Physical address of FDT blob in system RAM

   
Kernel 소스 :
  arch/arm/kernel/atags_parse.c
  arch/arm/boot/compressed/atags_to_fdt.c

관련링크
  http://devicetree.org/Boot_Environment    ( Mapping 반드시 참조 )

Machine ID 와 ATAG 관련설명
  http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html (ATAG)
  http://devicetree.org/BootingLinuxOnArm  ( Booting 과정 설정)
  http://stackoverflow.com/questions/21014920/arm-linux-atags-vs-device-tree  (ATAGS , DT차이)
  https://www.kernel.org/doc/Documentation/arm/Booting (BOOTing 과정 설명)


4. Device Tree 사용한 Kernel 분석 

  • AM437x/AM335x일 경우,
Linux Kernel Image는 DTB파일은 받아 이 설정값 기준으로 각각의 Device Driver를 설정을 하게된다.
다만 주의해야할 것은 Kernel Config에서 관련설정을 해야한다.

이제 EVM Board에 관련설정은 board-generic.c  DTB로 변경하여 설정하게 되므로, 동작방식을 아래의 Kernel 소스에서 부터 확인해볼 필요가 있다.

  • Kernel config 확인
$ vi .config //AM437x 일 경우
...
#
# OMAP Feature Selections
#
CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_MUX=y
CONFIG_OMAP_MUX_DEBUG=y
CONFIG_OMAP_MUX_WARNINGS=y
CONFIG_OMAP_32K_TIMER=y
CONFIG_OMAP_DM_TIMER=y
CONFIG_OMAP_PM_NOOP=y
CONFIG_MACH_OMAP_GENERIC=y
CONFIG_ARCH_OMAP=y
# CONFIG_ARCH_OMAP3 is not set
# CONFIG_ARCH_OMAP4 is not set
# CONFIG_SOC_OMAP5 is not set
# CONFIG_SOC_AM33XX is not set
CONFIG_SOC_AM43XX=y
# CONFIG_SOC_DRA7XX is not set
CONFIG_ARCH_OMAP2PLUS=y
....

$ vi .config   //AM335x 일 경우 
...
#
# TI OMAP/AM/DM/DRA Family
#
# CONFIG_ARCH_OMAP3 is not set
# CONFIG_ARCH_OMAP4 is not set
# CONFIG_SOC_OMAP5 is not set
CONFIG_SOC_AM33XX=y
# CONFIG_SOC_AM43XX is not set
# CONFIG_SOC_DRA7XX is not set
CONFIG_ARCH_OMAP2PLUS=y
...


  • DT_MACHINE_START 확인
기존에 사용하던 MACHINE_START 대신 Device Tree는 DT_MACHINE_START를 사용하므로 관련부분 확인

$ grep -r DT_MACHINE_START ./arch/arm/mach-omap2/ // 본인 보드의 Board_init을 찾는다. DT_MACHINE_START
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP3_N900_DT, "Nokia RX-51 board")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP3_GP_DT, "Generic OMAP3-GP (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(AM3517_DT, "Generic AM3517 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(TI814X_DT, "Generic ti814x (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(TI816X_DT, "Generic ti816x (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(OMAP5_DT, "Generic OMAP5 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(DRA74X_DT, "Generic DRA74X (Flattened Device Tree)")
./arch/arm/mach-omap2/board-generic.c:DT_MACHINE_START(DRA72X_DT, "Generic DRA72X (Flattened Device Tree)")


$ vi ./arch/arm/mach-omap2/board-generic.c
.....
#ifdef CONFIG_SOC_AM43XX
static const char *const am43_boards_compat[] __initconst = {
    "ti,am4372",
    "ti,am43",
    NULL,
};

DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)")
    .l2c_aux_val    = OMAP_L2C_AUX_CTRL,
    .l2c_aux_mask   = 0xcf9fffff,
    .l2c_write_sec  = omap4_l2c310_write_sec,
    .map_io     = am33xx_map_io,                  // vi ./arch/arm/mach-omap2/io.c
    .init_early = am43xx_init_early,              // vi ./arch/arm/mach-omap2/io.c
    .init_late  = am43xx_init_late,               // vi ./arch/arm/mach-omap2/io.c
    .init_irq   = omap_gic_of_init,               // vi ./arch/arm/mach-omap2/omap4-common.c
    .init_machine   = omap_generic_init,          // vi ./arch/arm/mach-omap1/board-generic.c
    .init_time  = omap3_gptimer_timer_init,       // vi ./arch/arm/mach-omap2/timer.c 
    .dt_compat  = am43_boards_compat,             // 위에 정의  
    .restart    = omap44xx_restart,               // vi ./arch/arm/mach-omap2/omap4-restart.c
MACHINE_END
#endif
.......
$ vi ./arch/arm/mach-omap2/board-generic.c   // 본인 보드의 설정을 확인하자 machine_desc 내용, 이 부분은 동적으로 설정이 되기때문에 찾아봐도 존재하지 않는다. 
....
#ifdef CONFIG_SOC_AM33XX
static const char *const am33xx_boards_compat[] __initconst = {
    "ti,am33xx",
    NULL,
};

DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
    .reserve    = omap_reserve,
    .map_io     = am33xx_map_io,           // vi ./arch/arm/mach-omap2/io.c 
    .init_early = am33xx_init_early,       // vi ./arch/arm/mach-omap2/io.c 
    .init_machine   = omap_generic_init,   // vi ./arch/arm/mach-omap1/board-generic.c
    .init_late  = am33xx_init_late,        // vi ./arch/arm/mach-omap2/io.c 
    .init_time  = omap3_gptimer_timer_init, // vi ./arch/arm/mach-omap2/timer.c
    .dt_compat  = am33xx_boards_compat,     // 위에 정의 
    .restart    = am33xx_restart,           // vi ./arch/arm/mach-omap2/am33xx-restart.c
MACHINE_END
#endif
.....


  • Kernel 의 Linker Script 분석


$ vi arch/arm/kernel/vmlinux.lds   //kernel의 linkscript (AM43xx)
.......

 .init.arch.info : {              //MACHINE_START or DT_MACHIN_START
  __arch_info_begin = .;
  *(.arch.info.init)
  __arch_info_end = .;           //MACHINED_END
 }
 .init.tagtable : {              //ATAGS
  __tagtable_begin = .;     
  *(.taglist.init)
  __tagtable_end = .;
 }
 .init.pv_table : {              // phy to virtual , 이것은 이곳의 범위에 상관이 없어 넘어감
  __pv_table_begin = .;
  *(.pv_table)
  __pv_table_end = .;
 }
 .init.data : {
  *(.init.data) *(.meminit.data) *(.init.rodata) *(.meminit.rodata) . = ALIGN(8); __clk_of_table = .; *(__clk_of_table) *(__clk_of_table_end) . = ALIGN(8); __reservedmem_of_table = .; *(__reservedmem_of_table) *(__reservedmem_of_table_end) . = ALIGN(8); __clksrc_of_table = .; *(__clksrc_of_table) *(__clksrc_of_table_end) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(8); __irqchip_begin = .; *(__irqchip_of_table) *(__irqchip_of_end)
  . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;
  __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;
  __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;
  __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;
  . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)
 }
 .exit.data : {
  *(.exit.data) *(.memexit.data) *(.memexit.rodata)
 }
 __init_end = .;
....

$ vi arch/arm/kernel/vmlinux.lds   //kernel의 linkscript (AM33xx)
.......

 .init.arch.info : {              //MACHINE_START or DT_MACHIN_START
  __arch_info_begin = .;
  *(.arch.info.init)
  __arch_info_end = .;           //MACHINED_END
 }
 .init.tagtable : {              //ATAGS
  __tagtable_begin = .;     
  *(.taglist.init)
  __tagtable_end = .;
 }
 .init.pv_table : {              // phy to virtual , 이것은 이곳의 범위에 상관이 없어 넘어감
  __pv_table_begin = .;
  *(.pv_table)
  __pv_table_end = .;
 }
....


$ vi System.map   // AM43xx

c0813594 T __arch_info_begin
c0813594 t __mach_desc_GENERIC_DT.20839
c0813594 T __proc_info_end
c08135ec t __mach_desc_AM43_DT
c0813644 T __arch_info_end
c0813644 T __tagtable_begin
c0813644 t __tagtable_parse_tag_cmdline
c081364c t __tagtable_parse_tag_revision
c0813654 t __tagtable_parse_tag_serialnr
c081365c t __tagtable_parse_tag_ramdisk
c0813664 t __tagtable_parse_tag_videotext
c081366c t __tagtable_parse_tag_mem32
c0813674 t __tagtable_parse_tag_core
c081367c t __tagtable_parse_tag_initrd2
c0813684 t __tagtable_parse_tag_initrd
c081368c T __pv_table_begin
c081368c T __tagtable_end
c0813a70 T __pv_table_end
......

$ vi System.map   // 각 함수 확인 (AM33xx)
c09924e4 T __arch_info_begin
c09924e4 t __mach_desc_GENERIC_DT.24345
c09924e4 T __proc_info_end
c099254c t __mach_desc_AM33XX_DT
c09925b4 T __arch_info_end
c09925b4 T __tagtable_begin              // tagslist 에 들어가는 정보들  
c09925b4 t __tagtable_parse_tag_cmdline     // cmdline
c09925bc t __tagtable_parse_tag_revision    // revision 
c09925c4 t __tagtable_parse_tag_serialnr
c09925cc t __tagtable_parse_tag_videotext
c09925d4 t __tagtable_parse_tag_mem32
c09925dc t __tagtable_parse_tag_core
c09925e4 t __tagtable_parse_tag_initrd2
c09925ec t __tagtable_parse_tag_initrd
c09925f4 T __pv_table_begin
c09925f4 T __tagtable_end
c09927bc T __pv_table_end
....


  • MACHINE_START/END 와 DT_MACHINE_START
위에서 설명했듯이 위 두기능는 동일하며, machine_desc를 Device Tree를 사용하냐 Old Style이냐 따라 보면되겠다.

$ vi arch/arm/include/asm/mach/arch.h  

struct machine_desc {
    unsigned int        nr;     /* architecture number  */
    const char      *name;      /* architecture name    */
    unsigned long       atag_offset;    /* tagged list (relative) */
    const char *const   *dt_compat; /* array of device tree
                         * 'compatible' strings */

    unsigned int        nr_irqs;    /* number of IRQs */

#ifdef CONFIG_ZONE_DMA
    phys_addr_t     dma_zone_size;  /* size of DMA-able area */
#endif

    unsigned int        video_start;    /* start of video RAM   */
    unsigned int        video_end;  /* end of video RAM */

    unsigned char       reserve_lp0 :1; /* never has lp0    */
    unsigned char       reserve_lp1 :1; /* never has lp1    */
    unsigned char       reserve_lp2 :1; /* never has lp2    */
    enum reboot_mode    reboot_mode;    /* default restart mode */
    unsigned        l2c_aux_val;    /* L2 cache aux value   */
    unsigned        l2c_aux_mask;   /* L2 cache aux mask    */
    void            (*l2c_write_sec)(unsigned long, unsigned);
    const struct smp_operations *smp;   /* SMP operations   */
    bool            (*smp_init)(void);
    void            (*fixup)(struct tag *, char **);
    void            (*dt_fixup)(void);
    long long       (*pv_fixup)(void);
    void            (*reserve)(void);/* reserve mem blocks  */
    void            (*map_io)(void);/* IO mapping function  */
    void            (*init_early)(void);
    void            (*init_irq)(void);
    void            (*init_time)(void);
    void            (*init_machine)(void);
    void            (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
    void            (*handle_irq)(struct pt_regs *);
#endif
    void            (*restart)(enum reboot_mode, const char *);
};






#define MACHINE_START(_type,_name)          \
static const struct machine_desc __mach_desc_##_type    \
 __used                         \
 __attribute__((__section__(".arch.info.init"))) = {    \
    .nr     = MACH_TYPE_##_type,        \
    .name       = _name,

#define MACHINE_END             \
};

#define DT_MACHINE_START(_name, _namestr)       \
static const struct machine_desc __mach_desc_##_name    \
 __used                         \
 __attribute__((__section__(".arch.info.init"))) = {    \
    .nr     = ~0,               \
    .name       = _namestr,

#endif

  • Kernel config
아래와 같이 ATAGS와 관련있는 파일을 확인

$ vi .config 
....
CONFIG_ATAGS=y                 # arch/arm/kernel/atags_parse.c
...
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y   # arch/arm/boot/compressed/atags_to_fdt.c
CONFIG_ATAGS_PROC=y            # arch/arm/kernel/atags_proc.c
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
....


각 옵션에 대해 간단히 알아보자.
  1. CONFIG_ATAGS=y
  2. CONFIG_ARM_ATAG_DTB_COMPAT=y
  3. CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y

상위에서 ATAG는 DTB를 받기위한 한 통로이며, 물론 다르게 구성하여 확장도 가능하겠지만 현재는 그렇게 동작되지는 않는다.

ATAGS의 주소는 U-BOOT에서 FDT(Flattened Device Tree)라는 주소로 이를 받고, uImage와 DTB는 결합이 될 것이다.

  https://www.denx.de/wiki/DULG/UBootCmdFDT



  • Kernel에서 Machine ID 확인 
아래와 같이 arch/arm/tools/mach-types에서 확인가능

$ vi arch/arm/tools/mach-types
#
# machine_is_xxx        CONFIG_xxxx             MACH_TYPE_xxx           number
#
....
omap_generic            MACH_OMAP_GENERIC       OMAP_GENERIC            452
...
$ vi .config
....
CONFIG_MACH_OMAP_GENERIC=y   # 상위와 동일 
CONFIG_ARCH_OMAP=y
...


4.1 U-Boot 와 Kernel의 DTS 위치 및 호환성 ( DTB 공유)

Device Tree도 문법은 지속적으로 변경되겠지만, 최근 TI의 Sitara것을 보면 아래와 같이 AM335x의 경우 DTS File이 Kernel과 U-BOOT가 같이 존재하며 내용도 동일하다.
만약 UBOOT의 내용과 Kernel의 내용이 맞지 않는다면, 둘중 하나를 선택해서 사용해야할 것 같다

UBOOT or KERNEL의 DTS는 반드시 DTC가 존재해야 하며, Uboot도 DTB를 공유되어 사용되어진다.

보통 1st Boot Loader가 존재하며, 2nd Boot Loader (UBoot)를 사용하므로 DTB 역시 UBoot 와 Kernel 에서도 동일하게 사용하기 위해서 공유가 되어져야 할 것이다.

  • Devcie Tree의 Booting 방법 (참조)
처음에는 알지 못했는데, Kernel 뿐만 아니라 Uboot에도 DTB를 적용하여 이를 공유해 사용하면 될 것 같다.
  https://ahyuo79.blogspot.com/2015/08/am437x-kernel-device-tree.html

Uboot의 FDT Command
  https://www.denx.de/wiki/view/DULG/UBootCmdFDT

  • U-BOOT에서 Device Tree 위치 
$ cd board-support
$ cd u-boot*  // Uboot Source 로 이동 

$ ls arch/arm/dts // Uboot 용 Device Tree Syntax (Kernel과 동일)
-rw-r--r--  1 jhlee jhlee  9346 12월 15 09:05 am335x-bone-common.dtsi
-rw-rw-r--  1 jhlee jhlee 30487  3월 14 14:30 am335x-bone.dtb
-rw-r--r--  1 jhlee jhlee   618 12월 15 09:05 am335x-bone.dts
-rw-rw-r--  1 jhlee jhlee 31186  3월 14 14:30 am335x-boneblack.dtb
-rw-r--r--  1 jhlee jhlee  3377 12월 15 09:05 am335x-boneblack.dts
-rw-rw-r--  1 jhlee jhlee 30818  3월 14 14:30 am335x-bonegreen.dtb
-rw-r--r--  1 jhlee jhlee  1184 12월 15 09:05 am335x-bonegreen.dts
-rw-rw-r--  1 jhlee jhlee 36854  3월 14 14:30 am335x-evm.dtb
-rw-r--r--  1 jhlee jhlee 19058 12월 15 09:05 am335x-evm.dts
-rw-rw-r--  1 jhlee jhlee 35799  3월 14 14:30 am335x-evmsk.dtb
-rw-r--r--  1 jhlee jhlee 20720 12월 15 09:05 am335x-evmsk.dts
-rw-rw-r--  1 jhlee jhlee 31726  3월 14 14:30 am335x-icev2.dtb
-rw-r--r--  1 jhlee jhlee 10299 12월 15 09:05 am335x-icev2.dts
-rw-r--r--  1 jhlee jhlee 13955 12월 15 09:05 am33xx-clocks.dtsi
-rw-r--r--  1 jhlee jhlee 20273 12월 15 09:05 am33xx.dtsi
-rw-r--r--  1 jhlee jhlee 24483 12월 15 09:05 am4372.dtsi
-rw-r--r--  1 jhlee jhlee 22179 12월 15 09:05 am437x-gp-evm.dts
-rw-r--r--  1 jhlee jhlee 10493 12월 15 09:05 am437x-idk-evm.dts
-rw-r--r--  1 jhlee jhlee 17847 12월 15 09:05 am437x-sk-evm.dts
-rw-r--r--  1 jhlee jhlee 21643 12월 15 09:05 am43x-epos-evm.dts
-rw-r--r--  1 jhlee jhlee 16774 12월 15 09:05 am43xx-clocks.dtsi
-rw-r--r--  1 jhlee jhlee  6797 12월 15 09:05 am571x-idk.dts
-rw-r--r--  1 jhlee jhlee  7153 12월 15 09:05 am572x-idk.dts
-rw-r--r--  1 jhlee jhlee 20598 12월 15 09:05 am57xx-beagle-x15.dts
-rw-r--r--  1 jhlee jhlee  8073 12월 15 09:05 am57xx-idk-common.dtsi       
....


  • Kernel에서의 Device Tree 위치 
$ cd board-support
$ cd linux*  // Linux Kernel 로 이동 

$ ls arch/arm/boot/dts/
-rw-r--r--  1 jhlee jhlee  9346 12월 15 09:05 am335x-bone-common.dtsi
-rw-rw-r--  1 jhlee jhlee 30487  3월 14 14:30 am335x-bone.dtb
-rw-r--r--  1 jhlee jhlee   618 12월 15 09:05 am335x-bone.dts
-rw-rw-r--  1 jhlee jhlee 31186  3월 14 14:30 am335x-boneblack.dtb
-rw-r--r--  1 jhlee jhlee  3377 12월 15 09:05 am335x-boneblack.dts
-rw-rw-r--  1 jhlee jhlee 30818  3월 14 14:30 am335x-bonegreen.dtb
-rw-r--r--  1 jhlee jhlee  1184 12월 15 09:05 am335x-bonegreen.dts
-rw-rw-r--  1 jhlee jhlee 36854  3월 14 14:30 am335x-evm.dtb
-rw-r--r--  1 jhlee jhlee 19058 12월 15 09:05 am335x-evm.dts
-rw-rw-r--  1 jhlee jhlee 35799  3월 14 14:30 am335x-evmsk.dtb
-rw-r--r--  1 jhlee jhlee 20720 12월 15 09:05 am335x-evmsk.dts
-rw-rw-r--  1 jhlee jhlee 31726  3월 14 14:30 am335x-icev2.dtb
-rw-r--r--  1 jhlee jhlee 10299 12월 15 09:05 am335x-icev2.dts
-rw-r--r--  1 jhlee jhlee 13955 12월 15 09:05 am33xx-clocks.dtsi
-rw-r--r--  1 jhlee jhlee 20273 12월 15 09:05 am33xx.dtsi
-rw-r--r--  1 jhlee jhlee 24483 12월 15 09:05 am4372.dtsi
-rw-r--r--  1 jhlee jhlee 22179 12월 15 09:05 am437x-gp-evm.dts
-rw-r--r--  1 jhlee jhlee 10493 12월 15 09:05 am437x-idk-evm.dts
-rw-r--r--  1 jhlee jhlee 17847 12월 15 09:05 am437x-sk-evm.dts
-rw-r--r--  1 jhlee jhlee 21643 12월 15 09:05 am43x-epos-evm.dts
-rw-r--r--  1 jhlee jhlee 16774 12월 15 09:05 am43xx-clocks.dtsi
-rw-r--r--  1 jhlee jhlee  6797 12월 15 09:05 am571x-idk.dts
-rw-r--r--  1 jhlee jhlee  7153 12월 15 09:05 am572x-idk.dts
-rw-r--r--  1 jhlee jhlee 20598 12월 15 09:05 am57xx-beagle-x15.dts
-rw-r--r--  1 jhlee jhlee  8073 12월 15 09:05 am57xx-idk-common.dtsi       
....

댓글 없음 :