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
https://www.devicetree.org
- Ubuntu 에서 ARM Device 를 위하여 Device Tree를 사용 할 경우
- Device Tree 사용법 ( Spec 및 관련문서 중요)
http://www.devicetree.org/Device_Tree_Usage
http://www.devicetree.org/specifications/
- 현재 Device Tree의 적용되는 예
http://omappedia.org/wiki/Device_Tree (TI)
- 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
DTS는 C언어 처럼 include가 가능하여, DTSI를 사용한다.
arch/arm/boot/dts/
arch/powerpc/boot/dts/
1.3 DTC(Device Tree Compiler) 위치확인
DTC는 kernel에서 빌드되며 아래와 같이 Version이 존재하고, 관련 Source도 Kernel 내부에 존재한다.
- DTC의 빌드 : Kernel Config의 CONFIG_DTC=y 추가
- 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도 두가지방식
- OLD Style: 기존방식 MACHINE ID와 MACHINE_START/END 사용
- 1stNew Style: DTB와 uImage 분리되며, U-BOOT에서 uImage 와 DTB 주소 전달
- 2ndNew Style: uImage 와 DTB File을 포함 (Uboot에서 DTB를 전달필요없음)
- Kernel Image는 uImage or zImage로도 가능
- vmlinux : linux kernel의 ELF format으로 실행가능한 kernel이며 기본적인 kernel
- image : vmlinux 기반에서 objcopy에서 -O binary -R .comment -S
- zImage : vmlinux기반에서 linkscript 기반으로 piggy 및 head 와 gzip 등을 포함한 Kernel Image
- 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://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 생성
- DTB Data를 전달하는 두가지 방식
- uImage와 DTB를 합쳐서 설정하는 방식
- DTB 와 uImage를 분리하며, uboot에서 이를 전달하는 방식 (3.1/2/3 설명 )
2.2 Kernel설정 (1st New Style)
DTB와 Kernel이 분리된 경우 사용하며, 문서에도 보면 이부분을 선호하며, UBOOT에서 동적으로 맘대로 DTB만 변경만 하면 되기 때문에 편할 것으로 보인다.
2nd New Style 부분은 uImage와 DTB를 합치는 것이며 별도의 Kernel 설정이 필요하며 이부분은 생략
- ATAGS 사용 및 소개
Device Tree가 나오기전의 개념이며, 이것 단독으로 Device Tree를 사용할 수 없지만,이를 Device Tree에 적용하여 사용이 가능하다.
- Kernel Config 설정
- CONFIG_ATAGS //ATAGS 사용하여 TAG LIST로 받음
- CONFIG_ARM_ATAG_DTB_COMPAT // TAG LIST에서 DTB를 받아 호환
- CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER // TAG LIST DTB 포함
- CONFIG_ARM_APPENDED_DTB // DTB가 Kernel Image에 포함
- 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 사용)
앞에 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일 경우,
다만 주의해야할 것은 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 확인
$ 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
$ 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
$ 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 ....
각 옵션에 대해 간단히 알아보자.
- CONFIG_ATAGS=y
- CONFIG_ARM_ATAG_DTB_COMPAT=y
- 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 확인
$ 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 방법 (참조)
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 ....