8/10/2015

Device Tree Boot (TI-Sitara)

1. Device Tree 란? 

Device Tree는 Linux에서 BootLoader와 Kernel Hardware 설정을 간단하게 해주는 문법이며, 문법의 규칙에 따라
Device Driver들은 환경설정 가능하다.

이는 BootLoader 와 Linux Kernel 에서 SoC or MPU Hardware 의존적인 부분들을 보다 호환성을 좋게 사용하려는 것이다.
TI Chip뿐만 아니라 다른 곳에서도 많이 사용되니 이에 관련된 동작방식에 대해서 자료들을 구해서 정리하고자 한다.

DTS File을 여러개 만들어 놓고, DTS File의 설정변경하고,이를 DTC를 이용하여 최종으로 DTB File로 변환하여  Kernel Image은 변경하지 않고
DTB File을 이용하여 Kernel 및 Uboot의 내부의 설정을 변경하여 쉽게 변경하려는 구조이다.

다만, 사용되는 Kernel Image는 DTS의 Hardware 설정을 모두 지원을 한다는 가정하에 그렇게 사용이 가능하다.

2. 기존 Boot 방식과 Device Tree Boot 비교

기존의 Kernel의 Booting 방식과 Device Tree Kernel Booting 방식을 간단히 비교해보자 DM368을 기준으로 했지만, 모든 Embedded Linux가 거의 동일 할 것이다.

2.1 기존 Kernel Boot 방식 (Old Style)

이는 보통 Kernel 안에 존재하는 board-x.c 설정을 외부에서 할수 있도록하는 시스템이다. 
**board-x.c : arch/arm/mach-x/board-x.c

  1. U-BOOT에서 r1으로 Machine ID를 보낸다.
  2. Kernel은 이 ID 비교 후 다르면 에러 같을 경우
  3. init_machine()을 호출되어 진행 (MACHINE_START/END 부분 등록됨)
  4. 각각의 platform_driver를 확인하면 된다.

http://schedule2012.rmll.info/IMG/pdf/LSM2012_ArmKernelConsolidation_Petazzoni.pdf

















  • init_machine() 함수 
MACHINE_START와 MACHINE_END 사용 


2.2 Device Tree Kernel Boot 구조 ( New Style )

새로운 구조인 Device Tree 구조는 기존과 다르게 MACHINE_START 부분이 변경이 된다.

  • Device Tree를 사용할 경우
DT_MACHINE_START/DT_MACHINE_END 로 변경됨 

DT_MACHINE_START/DT_MACHINE_END를 사용하여, 동적 설정이 가능하며 호환성이 증가되는 기능이 있다.
이 부분을 분석하면 각각의 Hardware를 추상화하는 File을 Driver로 보내지며, 이를 설정한다.


  • DTS -> DTB ( Compile)
  1. dtb:  DTS 를 빌드하면 생성되는 Binary 파일 
  2. dts/dtsi: device tree syntax로 각각의 hardware 정보를 기술 


  • 동작방식
  1. BootLoader는 dtb를 memory에서 load를 진행
  2. BootLoader는 dtb를 r2주소를 Kernel에게 전달 
  3. Linux Kernel 은 dtb 기준으로 DT_MACHINE_START 부터 각각 compat 이름이 맞는것을 찾아 초기화
  4. 개별 driver 역시 ,dts의 compatible의 이름과 driver의 이름 맞는 것을 찾아 초기화하며, 설정


http://schedule2012.rmll.info/IMG/pdf/LSM2012_ArmKernelConsolidation_Petazzoni.pdf

핵심은 board-x.c의 호환성이며, MACHINE_START/END 동적 설정이 가능하다.


2.3 기존 Kernel Booting 방식 (Old Style의 예 DM368)

일반적인 U-BOOT와 Linux Kernel의 booting은 다음과 같으며, 다음은 DM368 IPNC Kernel 기준으로 설명을 하겠다

  • Kernel Source 간단히 분석

A. Kernel 에서 Board Type을 CONFIG_MACH_DAVINCI_DM368_IPNC로 설정

$ vi .config 

#
# DaVinci Board Type
#
# CONFIG_MACH_DAVINCI_DM365_EVM is not set
# CONFIG_MACH_DAVINCI_DM365_IPNC is not set
CONFIG_MACH_DAVINCI_DM368_IPNC=y


일반적으로 UBOOT는 Machine ID를 설정하여, Kernel에게 전달을 해준다.
그러므로, UBOOT에서 반드시 본인에 보드에 맞는 MACHINE ID를 설정을 해줘야 한다.

B. UBOOT에서 얻은 MACHINE ID와 비교하고 틀리면 에러로 표시 

$ vi ./include/generated/mach-types.h

#ifdef CONFIG_MACH_DAVINCI_DM368_IPNC
# ifdef machine_arch_type
#  undef machine_arch_type
#  define machine_arch_type     __machine_arch_type
# else
#  define machine_arch_type     MACH_TYPE_DAVINCI_DM368_IPNC
# endif
# define machine_is_davinci_dm368_ipnc()        (machine_arch_type == MACH_TYPE_DAVINCI_DM368_IPNC)
#else
# define machine_is_davinci_dm368_ipnc()        (0)
#endif


C. MACHINE_START/END의 함수등록 및 실행하여 EVM 초기화 
  1. init_machine 에서 초기에 등록해야할 device driver 들이 있으며, 관련설정들이 있다. 
  2. map_io:  memory를 mapping 해야 할경우 io_remap 
  3. timer  :  jiffies 와 scheduler와 연관되어 있다. 
  4. irq : interrupt로 필요한 interrupt를 등록

$ vi ./arch/arm/mach-davinci/board-dm368-ipnc.c

MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM36x IPNC")
        .boot_params    = (0x80000100),
        .map_io         = dm365_evm_map_io,
        .init_irq       = davinci_irq_init,
        .timer          = &davinci_timer,
        .init_machine   = dm368_evm_init,
MACHINE_END


D. Kernel의 Board_init 관련 정보확인  

    위의 MACHIN_START/END는 kernel link script의 arch/arm/kernel/vmlinux.lds 에서 .init.arch.info 들어가며, 이정보는 아래에서 확인가능.
    이는 arch/arm/include/asm/mach/arch.h

    위의 절차는 기본적으로 거의 동일하다.