8/13/2015

Device Tree 기반 소스수정 및 빌드 (U-Boot 와 Kernel)

1. Device Tree의 DTS 기본구조 및 Build 

Device Tree Syntax의 약자이며, Kernel 와  Uboot에 존재하며, 보통 두개의 dts 파일은 동일하다
  1. Kernel PATH:  arch/arm/boot/dts 
  2. Uboot PATH:  arch/arm/dts/

Device Tree Boot 방식
  https://ahyuo79.blogspot.com/2015/08/am437x-kernel-device-tree.html
  https://ahyuo79.blogspot.com/2015/08/device-tree-2-am437xam335x.html

Device Tree Syntax 구성방법
  https://ahyuo79.blogspot.com/2015/08/device-tree.html

지향하는 바는 DTS를 한번 설정하면 손쉽게 Uboot 와 Kernel 의 HW 설정변경 가능하도록하는 것이다.
물론 예외적으로 보면, 각 Image들과 결합을 하게되어 사용을 한다면, 따로 사용도 가능하겠다.

DTSI와 DTS파일이 존재하며, DTSI는 DTS에서 include하는 파일이며, 구조 또한 동일하다.
하지만, dt-bindings도 include를 하지만 header 파일로 사용이 된다.

Build 전에는 DTS와 DTSI만 존재하지만, Build 후에 DTB가 생성이된다.
  1. Main files: ./arch/arm/boot/dts 
  2. Include Files: ./arch/arm/boot/dts/include/dt-bindings
  3. Makefile./arch/arm/boot/dts/Makefile

1.1 AM437x Example
AM437x-GP-EVM 을 사용을 하며 TEST을 하고 있다.

$ ls arch/arm/boot/dts/am4*
am4372.dtsi             am437x-gp-evm.dtb  am437x-sk-evm.dtb  am43x-epos-evm-hdmi.dts  am43x-epos-evm.dts
am437x-gp-evm-hdmi.dts  am437x-gp-evm.dts  am437x-sk-evm.dts  am43x-epos-evm.dtb       am43xx-clocks.dtsi 


1.2 I.MX6 인 Example

I.MX6를 수정을 할때, 참고하던 Device Tree 예제들이며, 현재 Device Tree로 대부분의 CPU들이 지원을 하는 것 같다.
특히 한 것은 pinctl (iomuxc) 하는 방식이 TI와 다르게 사용되며, 관련부분은 별도로 봐야한다.

$ cat arch/arm/boot/dts/imx6ull-pinfunc.h  // 핀확인 IOMUXC Register 확인 (Kernel 소스)
$ vi arch/arm/boot/dts/imx6ul*   //

&iomuxc {
...
    pinctrl_can_int: canintgrp {
        fsl,pins = < 
            /*
               IOMUXC_SW_MUX_CTL_PAD : MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04
               IOMUXC_SW_PAD_CTL_PAD : 0x13010   (세부설정가능 Open Drain / Pull / Hysteresis Enable)
                                     : 0x80000000  상위 설정과 다르게 PAD Register를 변경을 막는다고 하는데, bit31/30은 자세한내용은 커널문서 
             */
            MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04    0x13010      /* SODIMM 73 */ 
        >;
    };
...
};

/sys/kernel/debug 가 되는 경우 아래와 같이 Pin 설정확인

$ ls /sys/kernel/debug/pinctrl/  // Target Device에서 debug 모드로 연결하여 확인 

$ cat /sys/kernel/debug/pinctrl/pinctrl-handles  // Target Device에서 설정확인 
Requested pin control handlers their pinmux maps:
device: 20e0000.iomuxc current state: default
........

$ cat /sys/kernel/debug/pinctrl/pinctrl-maps     // 관련정보 
$ cat /sys/kernel/debug/pinctrl/20e0000.iomuxc/pingroups


// GPIO 의 경우 sysfs에서 도 사용가능하지만, 직접 device tree의 모듈에 연결이 되어 사용가능하므로 주의
// 이때 아래와 같이 확인한 후 device tree에서 연결된 모듈의 gpio부분을 제거한 후 사용 

$ cat /sys/kernel/debug/gpio  // GPIO 정보 Debug 
..........
 gpio-112 (                    |peri_3v3            ) out hi
 gpio-114 (                    |sysfs               ) out lo
 gpio-116 (                    |sysfs               ) out lo
 gpio-117 (                    |sysfs               ) out lo
 gpio-118 (                    |sysfs               ) out lo
 gpio-119 (                    |sysfs               ) out lo
 gpio-122 (                    |sysfs               ) out lo
 gpio-123 (                    |can-stby            ) out hi
 gpio-127 (                    |sysfs               ) out lo

최근에 찾은 자료이며, i.MX6의 Device Tree 구조를 아래 사이트에서 쉽게 볼수 있어 업데이트한다.

  • i.MX의 Device Tree

i.MX6 관련내용 
  http://developer.toradex.com/device-tree-customization
  https://developer.toradex.com/device-tree-customization#2-imx-6ull-based-modules

/sys/kernel/debug 관련내용
  https://www.linuxtopia.org/online_books/linux_kernel/kernel_configuration/ch09s07.html

2. Device Tree 의 수정 및 사용법

Device Tree를 이해한다고, ARM BOOT를 다시 전체 분석을 할 필요는 없다.
지금 현재 제대로 동작을 하고 있으며, 필요한 모듈과 그기능을 찾아 그 부분만 수정을 하면 되기에 dts 파일과 dtsi파일을 이해하고 수정을 하면 되겠다.

2.1  DTS와 각 Driver의 구조 (AM437x 인 경우)

DTS파일과 각 Driver의 기본구조는 다음과 같다.
device tree의 기본동작 방식은 dts파일 안의 compatible의 이름과 driver의 맞을 경우 그 해당하는 driver에게 맞게 동작하게 되어있다.


그러므로, Kernel을 빌드후 다음과 같이 dts의 compatible의 이름을 검색하여 찾아 수정을하면 된다.



Device Tree의 위치는 위에서 설명했듯이 arch/arm/boot/dts/ 보면될 것이지만,관련된 부분을 전부 검색을 해보자.

  • Device Tree Source 관련소스 (driver) 검색  
  1. Kernel을 빌드 후, find들 이용하여 *.o file list 생성된다. 
  2. 이 file list들을 *.o에서 *.c 변경한다.
  3. 빌드된 file list의 *.c  중심으로 dts파일의 'compatible'로 검색진행 

$ cd kernel source 
$ find . -name '*.o' | sed -e 's/o$/c/g' | xargs grep -rs 'ti,am4372'
$ find . -name '*.o' | sed -e 's/o$/c/g' | xargs grep -rs 'arm,coretex-a9-gic'
$ find . -name '*.o' | sed -e 's/o$/c/g' | xargs grep -rs 'syscon'

or 

$ MY_KERENL=./kernel_source 
$ find $MY_KERENL -name '*.o' | sed -e 's/o$/c/g' | xargs grep -rs 'syscon' $MY_KERENL



2.2 DTS파일 수정 및 추가방법 (AM437x 경우)  

상위에서 DTS파일을 수정하고, 추가한다면, Kernel 내부의 Makefile 수정하면된다.
DTS파일을 빌드를 원한다면, Kernel로 이동 후에 빌드를 하자.

  • AM437x는 기본 Makefile 구성 (DTS관련부분만)
  1. Main Makefile ( U-BOOT , Kernel, Filesystem 모두 관리)
  2. Rule.make     ( 관련 설정)
  3. Kernel Source 내부 Makefile 

  • Main Makefile (DTB File Build 수정) 
현재 dtb 파일은 3개만 빌드를하게 만들었으며, 본인이 추가한다면 이곳에서 수정하자

$ vi Makefile
linux: linux-dtbs        ### linux kernel 부분 build 
        @echo =================================
        @echo     Building the Linux Kernel
        @echo =================================
        $(MAKE) -C $(LINUXKERNEL_INSTALL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) $(DEFCONFIG)
        $(MAKE) -j $(MAKE_JOBS) -C $(LINUXKERNEL_INSTALL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) zImage
        $(MAKE) -j $(MAKE_JOBS) -C $(LINUXKERNEL_INSTALL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
.....
# Kernel DTB build targets
linux-dtbs:
        @echo =====================================
        @echo     Building the Linux Kernel DTBs
        @echo =====================================
        $(MAKE) -C $(LINUXKERNEL_INSTALL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) $(DEFCONFIG)
        $(MAKE) -j $(MAKE_JOBS) -C $(LINUXKERNEL_INSTALL_DIR) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) am43x-epos-evm.dtb am437x-gp-evm.dtb am437x-sk-evm.dtb


  • Linux Kernel/Uboot 에서 상위 dtb 생성확인 (check DTB files)

$ cd board-support/linux*  // Linux Kernel Source 이동 

$ find . -name *dtb    // 상위 Makefile로 인하여 dtb 파일은 이미 3개 생성됨 확인  
./arch/arm/boot/dts/am437x-sk-evm.dtb
./arch/arm/boot/dts/am43x-epos-evm.dtb
./arch/arm/boot/dts/am437x-gp-evm.dtb
./include/config/arm/atag/dtb

  • Linux Kernel/Uboot 에서 내부 Makefile 수정 (for new DTS File)
상위 Makefile에서 3개만 빌드했기 때문에, 3개이며, 추가를 원한다면 상위 Makefile 수정하자.
새로운 dtb/dts을 추가한다고 하면 Kernel 내부의 dts 관련 Makefile 파일을 수정하자.

$ cd board-support/linux*  // Linux Kernel Source 이동 

$ vi .config  // Kernel Config 확인 
...
CONFIG_SOC_AM43XX=y
# CONFIG_SOC_DRA7XX is not set
CONFIG_ARCH_OMAP2PLUS=y
....

$ vi arch/arm/boot/dts/Makefile   // new dts file 추가 , 본인의 dts 설정파일 만들어 추가하자

dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        omap2430-sdp.dtb \
        omap2420-n800.dtb \
        omap2420-n810.dtb \
        omap2420-n810-wimax.dtb \
        omap3430-sdp.dtb \
        omap3-beagle.dtb \
        omap3-cm-t3730.dtb \
        omap3-sbc-t3730.dtb \
        omap3-devkit8000.dtb \
        omap3-beagle-xm.dtb \
        omap3-evm.dtb \
        omap3-evm-37xx.dtb \
        omap3-ldp.dtb \
        omap3-n900.dtb \
        omap3-n9.dtb \
        omap3-n950.dtb \
        omap3-overo-tobi.dtb \
        omap3-overo-storm-tobi.dtb \
        omap3-gta04.dtb \
        omap3-igep0020.dtb \
        omap3-igep0030.dtb \
        omap3-zoom3.dtb \
        omap4-panda.dtb \
        omap4-panda-a4.dtb \
        omap4-panda-es.dtb \
        omap4-var-som.dtb \
        omap4-sdp.dtb \
        omap4-sdp-es23plus.dtb \
        omap5-uevm.dtb \
        am335x-evm.dtb \
        am335x-evmsk.dtb \
        am335x-bone.dtb \
        am335x-boneblack.dtb \
        am335x-nano.dtb \
        am335x-base0033.dtb \
        am3517-craneboard.dtb \
        am3517-evm.dtb \
        am3517_mt_ventoux.dtb \
        am43x-epos-evm.dtb \
        am43x-epos-evm-hdmi.dtb \
        am437x-gp-evm.dtb \
        am437x-gp-evm-hdmi.dtb \
        am437x-sk-evm.dtb \
        dra7-evm.dtb \
        dra7-evm-lcd10.dtb \
        dra72-evm.dtb \
        dra72-evm-lcd10.dtb \
        am57xx-beagle-x15.dtb \
        am57xx-evm.dtb


  • Linux Kernel 내부 Makefile 에서 zImage 확인 
 zImage 빌드 할 경우 정확한 설정 확인하고, dtb와 연관성을 확인하자.
 아래의 *.cmd는 실행한 결과들이며, 이것을 확인을 하면, 어떻게 생성이 되었는지 쉽게  이해를 할수 있다.

$ cd board-support/linux*  // Linux Kernel Source 이동 

$ find . -name zImage   //zImage 와 Image 위치파악  
./arch/arm/boot/zImage

$ ls -a arch/arm/boot/    // zImage와 Image 생성 부분 분석 ( Makefile , *.cmd) 
.  ..  .Image.cmd  .gitignore  .zImage.cmd  Image  Makefile  bootp  compressed  dts  install.sh  zImage

$ cat ./arch/arm/boot/.zImage.cmd   //제대로 빌드되었다면 아래와 같이 확인가능 
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

$ vi arch/arm/boot/Makefile  // zImage 확인 
....
targets := Image zImage xipImage bootpImage uImage

ifeq ($(CONFIG_XIP_KERNEL),y)        // 현재 XIP 모드가 아님 ( NOR NAMD 이면, 가능하겠지만?)

$(obj)/xipImage: vmlinux FORCE
        $(call if_changed,objcopy)
        @$(kecho) '  Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'

$(obj)/Image $(obj)/zImage: FORCE
        @echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'
        @echo 'Only the xipImage target is available in this case'
        @false

else

$(obj)/xipImage: FORCE
        @echo 'Kernel not configured for XIP (CONFIG_XIP_KERNEL!=y)'
        @false

$(obj)/Image: vmlinux FORCE
        $(call if_changed,objcopy)
        @$(kecho) '  Kernel: $@ is ready'

$(obj)/compressed/vmlinux: $(obj)/Image FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed $@

$(obj)/zImage:  $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)                 ## OBJCOPYFLAGS 사용하며, objcopy를 이용하여 object를 binary를 만들때 사용한다  
        @$(kecho) '  Kernel: $@ is ready'          ## 자세한 내용은 Kernel 문서와 GCC 참조 

endif


  • Filesytem 에서 DTB와 Kernel zImage 확인 
Partition 과 Booting 부분에 있어, Partition은 2개이며, (fat32 와 filesystem 으로 존재) uboot는 fat32에 존재하며, 설정값도 그곳에 존재한다.
그리고 Filesystem 안의 boot에는  dtb 파일과 zImage는 File 형태로 존재하며 아래의 NFS File system에서도 동일하다.

$ cd board-support/linux*  // Linux Kernel Source 이동 
$ sudo cp arch/arm/boot/zImage /boot   // File System의 Boot에 저장 
$ sudo cp arch/arm/boot/dts/
.dtb /boot // File System의 Boot에 저장 $ targetNFS/boot //Kernel Image 와 *.dtb File 확인 (File system 안에 존재) $ ll drwxr-xr-x 2 jhlee jhlee 4096 7월 7 2015 ./ drwxr-xr-x 21 jhlee jhlee 4096 7월 7 2015 ../ lrwxrwxrwx 1 jhlee jhlee 40 7월 7 2015 am437x-gp-evm-hdmi.dtb -> devicetree-zImage-am437x-gp-evm-hdmi.dtb lrwxrwxrwx 1 jhlee jhlee 35 7월 7 2015 am437x-gp-evm.dtb -> devicetree-zImage-am437x-gp-evm.dtb lrwxrwxrwx 1 jhlee jhlee 35 7월 7 2015 am437x-sk-evm.dtb -> devicetree-zImage-am437x-sk-evm.dtb lrwxrwxrwx 1 jhlee jhlee 41 7월 7 2015 am43x-epos-evm-hdmi.dtb -> devicetree-zImage-am43x-epos-evm-hdmi.dtb lrwxrwxrwx 1 jhlee jhlee 36 7월 7 2015 am43x-epos-evm.dtb -> devicetree-zImage-am43x-epos-evm.dtb -rw-r--r-- 1 jhlee jhlee 49048 7월 7 2015 devicetree-zImage-am437x-gp-evm-hdmi.dtb -rw-r--r-- 1 jhlee jhlee 48112 7월 7 2015 devicetree-zImage-am437x-gp-evm.dtb -rw-r--r-- 1 jhlee jhlee 42675 7월 7 2015 devicetree-zImage-am437x-sk-evm.dtb -rw-r--r-- 1 jhlee jhlee 48544 7월 7 2015 devicetree-zImage-am43x-epos-evm-hdmi.dtb -rw-r--r-- 1 jhlee jhlee 47461 7월 7 2015 devicetree-zImage-am43x-epos-evm.dtb -rw-r--r-- 1 jhlee jhlee 105402448 7월 7 2015 vmlinux-3.14.43-g875c69b lrwxrwxrwx 1 jhlee jhlee 23 7월 7 2015 zImage -> zImage-3.14.43-g875c69b -rw-r--r-- 1 jhlee jhlee 4355472 7월 7 2015 zImage-3.14.43-g875c69b


  • TI-Kernel User Guide
  많은 부분이 아래에 내용에 나오며 아래부분을 참고하자.
  http://processors.wiki.ti.com/index.php/Linux_Kernel_Users_Guide


3. How To compile DTS Files
    위에서 언급했듯이 Kernel에서 직접 DTS를 빌드하고자 한다면, 아래와 같이 빌드하자.
    다만 새로 추가했다면, Kernel 내부 Makefile을 수정해야하며, DTS에 맞는 Kernel Config를 확인하자.

    $ cd board-support/linux*  // linux kernel 이동  
    $ ls .config // DTS에 맞는 config 설정이 되어있어야 함.
    $ make ARCH=arm CROSS_COMPILE=arm-xxxxx            
    $ make ARCH=arm CROSS_COMPILE=arm-xxxxx am43x-epos-evm.dtb
    

    만약, 위의 Makefile 파일에 추가 및 Makefile Config가 추가 되지 않았다면, target이 추가되지 않아 dtb를 compile를 할수가 없다.


    3.1 How To use DTC(Device Tree Compiler)

    위와 같이 Kernel Makefile를 이용하여 빌드하는 방법도 있지만,
    직접 dtc를 사용하여 compile 하는 방법도 가능하다

    *참고사항:  처음 Kernel source를 받으면, dtc file은 존재하지 않는다. build 도중 생김
    • DTC (Device Tree Compiler)
    $ cd board-support/linux*  // linux kernel 이동  
    $ ./scripts/dtc/dtc -I dtb -O dts -o (devicetree name).dts (devicetree name).dtb  // 직접 build 
    

      http://www.wiki.xilinx.com/Build+Device+Tree+Blob


    4. Device Tree Guide


    • Device Tree Syntax Spec (중요)  
    ** Device Tree의 Spec이 별도 존재하며 지속적으로 Update되고 있으므로, 각 Spec을 반드시 읽고 확인
      https://www.devicetree.org/specifications/ (문법)
      http://devicetree.org/Device_Tree_Usage  (수정방법)

    • TI Device Tree 사용법  
      http://omappedia.org/wiki/Device_Tree

    • Kernel/Uboot 내부 문서  
    ** Device Tree 사용 및 방법이 Chip Vendor마다 조금씩 다르므로 반드시 Kernel 문서를 확인해야함
      https://www.kernel.org/doc/Documentation/arm/Booting


    • 쉽게 Device Tree를 설명해주는 사이트  
    Device Tree를 쉽게 설명해주는 Guide이고, 아래의 문서에서 위의 그림을 복사하여 넣었다.

      http://www.elinux.org/images/a/ad/Arm-soc-checklist.pdf
      http://events.linuxfoundation.org/sites/events/files/slides/petazzoni-device-tree-dummies.pdf
      http://schedule2012.rmll.info/IMG/pdf/LSM2012_ArmKernelConsolidation_Petazzoni.pdf
      http://events.linuxfoundation.org/sites/events/files/slides/presentation_3.pdf
      http://lxr.free-electrons.com/source/Documentation/devicetree/booting-without-of.txt