레이블이 Linux-DeviceTree인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Linux-DeviceTree인 게시물을 표시합니다. 모든 게시물 표시

3/29/2020

Uboot 설정 과 Device Tree 처리방법

1. Uboot 구성 및 설정 

Uboot 기본 Manual
  https://www.denx.de/wiki/DULG/Manual

Uboot 의 전체 구성 과 설정방법
  https://gitlab.denx.de/u-boot/u-boot/raw/HEAD/README


  • Uboot 의 명령어
  https://www.denx.de/wiki/view/U-Bootdoc/BasicCommandSet
  https://www.digi.com/resources/documentation/digidocs/PDFs/90000852.pdf
  https://sites.google.com/site/manisbutareed/bringing-my-beagles-to-heel/u-boot-commands
  https://sites.google.com/site/manisbutareed/bringing-my-beagles-to-heel/selected-annotated-u-boot-commands


  • Uboot 환경값
  https://sites.google.com/site/manisbutareed/bringing-my-beagles-to-heel/u-boot-environment-variables


1.1 Uboot 와 DTB 결합구성 


  • Uboot Image 의 구성
  1. Uboot의 DTS를 DTC를 이용하여 DTB 파일생성 
  2. Uboot  Build를 진행 Uboot 파일생성
  3. cat를 이용하여 상위 두개 파일을 하나로 결합 
  4. mkimage를 이용하여 최종 Image 생성 

DTB Image를 최종 합쳐서 Uboot Image로 만들어서 제공

https://rocketboards.org/foswiki/Documentation/A10GSRDV1511GeneratingUBootAndUBootDeviceTree

  • Uboot Build 된곳에서 기본적인확인 
상위 그림처럼 Uboot 와 Uboot의 DTB를 결합하여 최종 Uboot 생성

$ cat dts/.dt.dtb.cmd  //Uboot DTB 파일 
cmd_dts/dt.dtb := cat arch/arm/dts/imx6sx-sdb-emmc.dtb > dts/dt.dtb

$ cat .u-boot-nodtb.bin.cmd  // 일반 Uboot bin 생성 (objcopy)
cmd_u-boot-nodtb.bin := arm-poky-linux-gnueabi-objcopy --gap-fill=0xff  -j .text -j .secure_text -j .secure_data -j .rodata -j .hash -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn -j .binman_sym_table -j .text_rest -j .dtb.init.rodata -j .efi_runtime -j .efi_runtime_rel -O binary   u-boot u-boot-nodtb.bin

$ cat .u-boot-dtb.bin.cmd    //Uboot 와 DTB 결합 
cmd_u-boot-dtb.bin := cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin

$ cat .u-boot.bin.cmd      // Uboot 이름변경 및 최종 uboot
cmd_u-boot.bin := cp u-boot-dtb.bin u-boot.bin   

$ cat .u-boot.imx.cmd // 최종 u-boot image
cmd_u-boot.imx := ./tools/mkimage -n u-boot.cfgout -T imximage -e 0x87800000 -d u-boot.bin u-boot.imx >u-boot.imx.log  && cat u-boot.imx.log

Uboot 와 Kernel 는 각각 DTS 존재하며, 두 DTS가 동일하지만, Uboot의 DTB 와 Kernel DTB는 각각 별도로 사용이 되어지고 있다.

내 개인적인 생각으로는 1st Boot Loader가 Uboot에게 전달하고, Uboot가 다시 Kernel에게 전달하여 전부 공유할 것이라고 생각했는데,
설정을 바꿔서 어떻게 공유할 수 있는지를 알아봐야겠다.
(환경변수 fdtcontroladdr 와  fdt_addr를 동일하게 공유)

Device Tree Boot 기본 구조
아래링크의 그림부분 참조
  https://ahyuo79.blogspot.com/2015/08/am437x-kernel-device-tree.html

TI-Sitara 의 Uboot / Kernel 의 Device Tree 관련부분 복습
  https://ahyuo79.blogspot.com/2015/08/kernel-boot-kernel-device-tree.html
  https://elinux.org/Device_Tree_Reference

Uboot 관련정보정리
  https://www.denx.de/wiki/pub/U-Boot/MiniSummitELCE2014/uboot2014_kconfig.pdf

1.2 Uboot 와 DTB 관련소스분석 

  • Uboot fdt 확인
=> version
U-Boot 2019.04-4.19.35-1.1.0+g4d37753 (May 13 2020 - 07:43:31 +0000)

arm-poky-linux-gnueabi-gcc (GCC) 8.3.0
GNU ld (GNU Binutils) 2.32.0.20190204

=> bdinfo
arch_number = 0x00000000
boot_params = 0x80000100
DRAM bank   = 0x00000000
-> start    = 0x80000000
-> size     = 0x40000000
baudrate    = 115200 bps
TLB addr    = 0xbfff0000
relocaddr   = 0xbff45000
reloc off   = 0x38745000
irq_sp      = 0xbdf359f0
sp start    = 0xbdf359e0
FB base     = 0x00000000
Early malloc usage: fc / 400
fdt_blob    = 0xbdf35a08  //uboot용 dtb (device tree blob) 주소

  • Uboot Config 설정확인 
$ vi .config   // Uboot Config 
....
#
# Partition Types
#
CONFIG_PARTITIONS=y
# CONFIG_MAC_PARTITION is not set
CONFIG_DOS_PARTITION=y
# CONFIG_ISO_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
CONFIG_EFI_PARTITION=y
CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=128
CONFIG_EFI_PARTITION_ENTRIES_OFF=0
CONFIG_PARTITION_UUIDS=y
# CONFIG_PARTITION_TYPE_GUID is not set
CONFIG_SUPPORT_OF_CONTROL=y
CONFIG_DTC=y

#
# Device Tree Control
#
## 아래 설정으로 Uboot에서 Device Tree 사용 (fdt 사용가능)
CONFIG_OF_CONTROL=y          
# CONFIG_OF_BOARD_FIXUP is not set
# CONFIG_OF_LIVE is not set
## 아래 설정때문에 cat u-boot.bin u-boot.dtb >image.bin 결합 
CONFIG_OF_SEPARATE=y
# CONFIG_OF_EMBED is not set
# CONFIG_OF_BOARD is not set
# CONFIG_OF_PRIOR_STAGE is not set
CONFIG_DEFAULT_DEVICE_TREE="imx6sx-sdb-emmc"
# CONFIG_MULTI_DTB_FIT is not set
CONFIG_MKIMAGE_DTC_PATH="dtc"

#
# Environment
#
# CONFIG_ENV_DEFAULT_NOWHERE is not set
# CONFIG_ENV_IS_IN_EEPROM is not set
# CONFIG_ENV_IS_IN_FAT is not set
# CONFIG_ENV_IS_IN_EXT4 is not set
# CONFIG_ENV_IS_IN_FLASH is not set
CONFIG_ENV_IS_IN_MMC=y
.....


  • Uboot Linker Script 
$ vi arch/arm/cpu/u-boot.lds  

        .rel_dyn_end :
        {
                *(.__rel_dyn_end)
        }

        .end :
        {
                *(.__end)
        }

        _image_binary_end = .;

//binary 로 변경시 아래부분은 필요없음 

        /*
         * Deprecated: this MMU section is used by pxa at present but
         * should not be used by new boards/CPUs.
         */
        . = ALIGN(4096);
        .mmutable : {
                *(.mmutable)
        }
.....
$ vi u-boot.map // System.map 재확인 

  • Uboot Source 확인
Uboot Config 기반으로 소스확인

$ vi common/board_r.c
......
static init_fnc_t init_sequence_r[] = {
        initr_trace,
        initr_reloc,
...
#ifdef CONFIG_MMC
        initr_mmc,
#endif
        initr_env,
....
        run_main_loop,
};

static int initr_env(void)
{
        /* initialize environment */
        if (should_load_env())
                env_relocate();
        else
                set_default_env(NULL, 0);
// 매번 Booting 때마다 fdtcontroladdr 변수설정하기 때문에 User가 변경해도 소용없음 
// Uboot에서 printenv로 확인가능하며 상위 CONFIG확인 
#ifdef CONFIG_OF_CONTROL
        env_set_hex("fdtcontroladdr",
                    (unsigned long)map_to_sysmem(gd->fdt_blob));  
#endif

        /* Initialize from environment */
        load_addr = env_get_ulong("loadaddr", 16, load_addr);

        return 0;
}

상위 설정대로 했을 경우 아래 bold 체가 실행

$ vi lib/fdtdec.c  // Uboot의 dtb부분 처리를 이해가능 

#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
/*
 * For CONFIG_OF_SEPARATE, the board may optionally implement this to
 * provide and/or fixup the fdt.
 */
__weak void *board_fdt_blob_setup(void)
{
        void *fdt_blob = NULL;
#ifdef CONFIG_SPL_BUILD
        /* FDT is at end of BSS unless it is in a different memory region */
        if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
                fdt_blob = (ulong *)&_image_binary_end;
        else
                fdt_blob = (ulong *)&__bss_end;
#else
        //CONFIG_OF_SEPARATE만 사용해서 uboot 끝에서 fdt를 가져옴 (Linker Script 참조)
        /* FDT is at end of image */
        fdt_blob = (ulong *)&_end;     
#endif
        return fdt_blob;
}
#endif

int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL)   // 현재설정 CONFIG_OF_CONTROL=y

# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) // 현재 미설정 # CONFIG_MULTI_DTB_FIT is not set
        void *fdt_blob;
# endif

# ifdef CONFIG_OF_EMBED  // 현재 미설정 # CONFIG_OF_EMBED is not set
        /* Get a pointer to the FDT */
#  ifdef CONFIG_SPL_BUILD // 현재 미설정 
        gd->fdt_blob = __dtb_dt_spl_begin;
#  else
        gd->fdt_blob = __dtb_dt_begin;
#  endif
# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) // 현재 이부분만 실행 
        /* Allow the board to override the fdt address. */
        gd->fdt_blob = board_fdt_blob_setup();  // 상위함수 참고 CONFIG_OF_BOARD는 미설정
# elif defined(CONFIG_OF_HOSTFILE)
        if (sandbox_read_fdt_from_file()) {
                puts("Failed to read control FDT\n");
                return -1;
        }
# endif
# ifndef CONFIG_SPL_BUILD  // 현재 미설정 
        /* Allow the early environment to override the fdt address */
#  if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)   // 현재 미설정 # CONFIG_OF_PRIOR_STAGE is not set
        gd->fdt_blob = (void *)prior_stage_fdt_address;
#  else
// 상위에서 설정된 gd->fdt_blob 변수 fdtcontroladdr의 기본값으로 읽어옴 
//bdinfo 와 printenv 확인가능 
        gd->fdt_blob = map_sysmem
                (env_get_ulong("fdtcontroladdr", 16,
                               (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); 
#  endif
# endif

# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)   // 현재미설정 # CONFIG_MULTI_DTB_FIT is not set
        /*
         * Try and uncompress the blob.
         * Unfortunately there is no way to know how big the input blob really
         * is. So let us set the maximum input size arbitrarily high. 16MB
         * ought to be more than enough for packed DTBs.
         */
        if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
                gd->fdt_blob = fdt_blob;

        /*
         * Check if blob is a FIT images containings DTBs.
         * If so, pick the most relevant
         */
        fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
        if (fdt_blob) {
                gd->multi_dtb_fit = gd->fdt_blob;
                gd->fdt_blob = fdt_blob;
        }

# endif
#endif

        return fdtdec_prepare_fdt();
}

이전의 Uboot 관련소스
  https://lists.denx.de/pipermail/u-boot/2012-July/127516.html
  https://gitlab.labs.nic.cz/turris/u-boot-turris/commit/eea63e05d0b7f54e7aa39725015483972c71cb3c

  • Uboot의 DTB  설정확인
$ vi arch/arm/dts/Makefile
....
dtb-$(CONFIG_MX6SX) += \
        imx6sx-14x14-arm2.dtb \
        imx6sx-17x17-arm2.dtb \
        imx6sx-17x17-arm2-ecspi.dtb \
        imx6sx-17x17-arm2-gpmi-weim.dtb \
        imx6sx-19x19-arm2.dtb \
        imx6sx-19x19-arm2-ecspi.dtb \
        imx6sx-19x19-arm2-gpmi-weim.dtb \
        imx6sx-sabreauto.dtb \
        imx6sx-sdb.dtb \
        imx6sx-sdb-emmc.dtb
.....


1.3 Uboot 의 Flattened Device Tree (FDT)

Uboot는 DTB File을 Memory 에 Load하여 기본 확인가능하며, 이를 수정도 가능한 명령이 fdt 명령어이다.
uImage 에서 사용하게 될 dtb, 즉 kernel 용 dtb를 fdt 명령어를 이용하여 이를 확인해보자.

fdt 명령어 설명 (세부명령어 참조)
  https://www.denx.de/wiki/view/DULG/UBootCmdFDT#Section_5.9.7.2.
  https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841676/U-Boot+Flattened+Device+Tree

  • Uboot 에서 Kernel의 DTB 정보확인 
Kernel에서 사용하게될 DTB 정보확인

=>pri
...
mmcdev=3
mmcpart=1
fdt_addr=0x83000000
fdt_file=undefined.dtb
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}   
.....
=> setenv fdt_file imx6sx-sdb-emmc.dtb  //DTB File 이름변경 

=> run loadfdt        //상위 명령어 실행 (eMMC or SDcard의 Device의 Partition에서 File 읽기 
49954 bytes read in 15 ms (3.2 MiB/s)

=> fdt addr ${fdt_addr}  // FDT address 설정 

=> fdt list  // DTB 파일을 볼수 있음 
....
=> fdt print // DTB 파일을 세부적으로 확인 
....

1.4 Uboot Env 분석 및 Hush Shell Script 확장 

i.MX6의 경우 이전에 TI의 Uboot Env보다 좀 더 잘 구성이 되어있어 이부분을 간단정리

=> pri
baudrate=115200
boot_fdt=try
bootargs=console=ttymxc0,115200 rdinit=/linuxrc clk_ignore_unused
bootcmd=run findfdt; mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; else run netboot; fi
bootcmd_mfg=run mfgtool_args;if iminfo ${initrd_addr}; then if test ${tee} = yes; then bootm ${tee_addr} ${initrd_addr} ${fdt_addr}; else bootz ${loadaddr} ${initrd_addr} ${fdt_addr}; fi; else echo "Run fastboot ..."; fastboot 0; fi;
bootdelay=3
bootscript=echo Running bootscript from mmc ...; source   // source command를 이용하여 boot.scr 실행 (default loadaddr) 
console=ttymxc0
emmc_ack=0
emmc_dev=3
eth1addr=c2:42:5a:9f:cd:09
ethact=ethernet@02188000
ethaddr=26:E1:2C:C4:C7:C6
ethprime=eth0
fastboot_bytes=adc00
fastboot_dev=mmc
fdt_addr=0x83000000       // Kernel용 DTB 주소 (DRAM) 
fdt_file=undefined        // Kernel용 DTB File 이름
fdt_high=0xffffffff       // DTB MAX DRAM MAX 
fdtcontroladdr=bdf35a08  // Uboot 용 DTB 주소 (DRAM)  
filesize=adc00
findfdt=if test $fdt_file = undefined; then setenv fdt_file imx6sx-sdb-emmc.dtb; fi;
image=zImage
initrd_addr=0x86800000
initrd_high=0xffffffff
ip_dyn=yes
kboot=bootz
loadaddr=0x80800000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};  // eMMC에서 bootscript 읽어서 쉽게확장
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file} // Kernel DTB File 읽기
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}  // Kernel Image
loadm4image=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${m4image} // qspi용 Kernel Image로 추정
loadtee=fatload mmc ${mmcdev}:${mmcpart} ${tee_addr} ${tee_file}  // 보안 boot 
m4_qspi_cs=2
m4boot=sf probe 1:${m4_qspi_cs}; bootaux 0x78000000
m4image=m4_qspi.bin
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc clk_ignore_unused
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
mmcautodetect=yes
mmcboot=echo Booting from mmc ...; run mmcargs; if test ${tee} = yes; then run loadfdt; run loadtee; bootm ${tee_addr} - ${fdt_addr}; else if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi; fi;
mmcdev=3
mmcpart=1
mmcroot=/dev/mmcblk3p2 rootwait rw
netargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...; run netargs; if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${image}; if test ${tee} = yes; then ${get_cmd} ${tee_addr} ${tee_file}; ${get_cmd} ${fdt_addr} ${fdt_file}; bootm ${tee_addr} - ${fdt_addr}; else if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;fi;
panel=Hannstar-XGA
script=boot.scr  // FAT에서 boot.scr를 만들어 설정확장
sd_dev=3
serial#=121a59d4f21fe636
soc_type=imx6sx
tee=no
tee_addr=0x84000000
tee_file=uTee-6sxsdb
update_m4_from_sd=if sf probe 1:${m4_qspi_cs}; then if run loadm4image; then setexpr fw_sz ${filesize} + 0xffff; setexpr fw_sz ${fw_sz} / 0x10000; setexpr fw_sz ${fw_sz} * 0x10000; sf erase 0x0 ${fw_sz}; sf write ${loadaddr} 0x0 ${filesize}; fi; fi


  • i.MX6의 경우 HW bootmode에 따라 bootcmd의 실행변경
  1. bootcmd: 일반 boot  Mode
  2. bootcmd_mfg: Download Mode (uuu라는 Program을 이용하여 fastboot이용)

  • Download Mode (fastboot이용)
i.MX6는 Download Mode 일 경우 USB를 통해서 Window/Linux의 uuu(mfgtools) Program을 이용하여 boot가 가능하다.
PC (USB Host) / i.MX6 (USB Device) 로 동작이되며, Uboot에서 fastboot를 이용하여 usb로 각 Data를 Download를 하고, eMMC or SDCard를 Write를 진행한다.
PC용 fastboot로는 연결해보지 못하고 오직 uuu라는 Program만 사용해봄

  • bootcmd 일 경우 
상위를 간단히 분석을 해보면 확장을 위해서 별도의 Uboot Script 파일을 읽어 User에서 Uboot의 설정을 변경가능하도록 만들었다.

  • loadbootscript (확장의 용이성)
Linux의 User에서 수정가능한 Uboot Script(boot.scr)가 존재하며, Linux User는 Uboot Env를 쉽게 이를 이용하여 변경이 가능하다.

TI-Sitara Uboot Script 및 Device Tree 설정
  https://ahyuo79.blogspot.com/2015/08/uboot-script-device-tree.html


1.5 Uboot Env 값 고정값으로 설정 

Env값들 중 변경 불가능 값들이 존재하여 관련된 소스분석 아래와 같이 board init 할때 마다 env_set 관련 function을 이용하여 직접 설정

$ cd uboot
$ vi include/configs/mx6sxsabresd.h   // 기본적인 uboot의 default env 값으로 saveenv 로 user가 각각 변경가능

#define CONFIG_EXTRA_ENV_SETTINGS \       //default env 값들 (saveenv 변경가능하지만, 변경불가능한 값 원인분석)
...............

#define CONFIG_BOOTCOMMAND \             // bootcmd 값  (saveenv 변경가능) 
           "run findfdt; " \
           "mmc dev ${mmcdev}; if mmc rescan; then " \
                   "if run loadbootscript; then " \
                           "run bootscript; " \
                   "else " \
                           "if run loadimage; then " \
                                   "run mmcboot; " \
                           "else run netboot; " \
                           "fi; " \
                   "fi; " \
           "else run netboot; fi"

//mmcdev 와 mmcroot의 경우 saveenv로 변경을해도 board_init 할때마다 새로설정됨  
$ vi board/freescale/common/mmc.c  
....
void board_late_mmc_env_init(void)
{
        char cmd[32];
        char mmcblk[32];
        u32 dev_no = mmc_get_env_dev();

        if (!check_mmc_autodetect())
                return;

//mmcdev 값 고정  , saveenv로 변경해도 기본값으로 설정 
        env_set_ulong("mmcdev", dev_no);

//mmcroot 값 고정 , saveenv로 변경해도 기본값으로 설정 
        /* Set mmcblk env */
        sprintf(mmcblk, "/dev/mmcblk%dp2 rootwait rw",
                mmc_map_to_kernel_blk(dev_no));
        env_set("mmcroot", mmcblk);

        sprintf(cmd, "mmc dev %d", dev_no);
        run_command(cmd, 0);
}


2. Uboot 의 Command Script 관리 

예전의 Uboot 보다 점점 많은 명령어를 지원해주고 있으며, fastboot를 비롯하여, 각종 filesystem도 마음대로 접근이 가능하며,
다양한 Hardware Interface도 지원을 해주고 있어 Hush shell 를 잘 이용하면 일반 Shell Script 못지않게 잘 사용할 수 있을 것 같다.

각종 사용되어지는 Image 관리부터 각각의 Interface check 기능 및다양한 Program을 쉽게 작성이 가능할 것 같다.

Hush Shell Script
  https://sites.google.com/site/manisbutareed/bringing-my-beagles-to-heel/5-to-be-continued

// Android의 fastboot 기능 
fastboot  - run as a fastboot usb or udp device
// Partition 
gpt       - GUID Partition Table
part      - disk partition related commands

// File system 관리 명령어 
fstype    - Look up a filesystem type
fatsize   - determine a file's size

ext2load  - load binary file from a Ext2 filesystem
ext2ls    - list files in a directory (default /)
ext4load  - load binary file from a Ext4 filesystem
ext4ls    - list files in a directory (default /)
ext4size  - determine a file's size
ext4write - create a file in the root directory

fatinfo   - print information about filesystem
fatload   - load binary file from a dos filesystem
fatls     - list files in a directory (default /)
fatmkdir  - create a directory
fatrm     - delete a file
fatsize   - determine a file's size
fatwrite  - write file into a dos filesystem

// DTB 관리 
fdt       - flattened device tree utility commands


2.1  Uboot의 mmc command 사용


=> mmc
mmc - MMC sub system

Usage:
mmc info - display info of the current MMC device
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
mmc rescan
mmc part - lists available partition on current mmc device
mmc dev [dev] [part] - show or set current mmc device [partition]
mmc list - lists available devices
mmc hwpartition [args...] - does hardware partitioning
  arguments (sizes in 512-byte blocks):
    [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes
    [gp1|gp2|gp3|gp4 cnt [enh] [wrrel {on|off}]] - general purpose partition
    [check|set|complete] - mode, complete set partitioning completed
  WARNING: Partitioning is a write-once setting once it is set to complete.
  Power cycling is required to initialize partitions after set to complete.
mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode
 - Set the BOOT_BUS_WIDTH field of the specified device
mmc bootpart-resize   
 - Change sizes of boot and RPMB partitions of specified device
mmc partconf dev [boot_ack boot_partition partition_access]
 - Show or change the bits of the PARTITION_CONFIG field of the specified device
mmc rst-function dev value
 - Change the RST_n_FUNCTION field of the specified device
   WARNING: This is a write-once field and 0 / 1 / 2 are the only valid values.
mmc setdsr  - set DSR register value

MMC 사용예제
  https://forums.xilinx.com/t5/ACAP-and-SoC-Boot-and/U-boot-Mmc-read-write/td-p/891742

  • mmc 기본확인
=> mmc list
FSL_SDHC: 1
FSL_SDHC: 2 (SD)
FSL_SDHC: 3 (eMMC)

=> mmc dev 3   //mmc device 선택 
switch to partitions #0, OK
mmc3(part 0) is current device

=> mmc part

Partition Map for MMC device 3  --   Partition Type: DOS

Part    Start Sector    Num Sectors     UUID            Type
  1     8192            45668           304dec68-01     0c Boot
  2     57344          445688          304dec68-02     83
  3     507904          524288          304dec68-03     83

=> mmc dev 2  //mmc device 선택 
switch to partitions #0, OK
mmc2 is current device

=> mmc part

Partition Map for MMC device 2  --   Partition Type: DOS

Part    Start Sector    Num Sectors     UUID            Type
  1     129             3911551         02751898-01     0c


  • mmc erase/write/read 방법
//SD Card의 Partition1 에서 File read 
=> fatload mmc 2:1 ${loadaddr} core-lora-image-imx6sxsabresd.wic 
528482304 bytes read in 35944 ms (14 MiB/s)

=> mmc dev 3   //mmc device 선택 
switch to partitions #0, OK
mmc3(part 0) is current device

=> pri loadaddr
loadaddr=0x80800000

//0x82400000  = 0x80800000 + 0x1C00000 ( 57344*512)
// Start Sector 0xE000(57344) 
// Num Sectors 0x6CCF8‬(445688)
// mmc read/write/erase HEX로 밖에 동작이 안됨 

=> mmc erase 0xE000 0x6CCF8‬ //eMMC erase
MMC erase: dev # 3, block # 57344, count 445688 ...

=> mmc write 0x82400000 0xE000 0x6CCF8‬ //eMMC Write 
MMC write: dev # 3, block # 57344, count 445688 ... 445688 blocks written: OK

=> mmc read 0x82400000 0xE000 0x6CCF8‬ //eMMC Write 
MMC read: dev # 3, block # 57344, count 445688 ... 445688 blocks read: OK

상위 정보는 linux application에서 fdisk -l 의 정보와 동일하며, image는 dd를 이용하여 편집가능

2.2 Uboot Script 생성

상위에서 사용했던 방법들을 간단히 정리하여 Script로 만들어서 이를 확장하는 방법을 알아보자.


  • 환경변수로 분할한 후 마지막에 연결
SDcard에서 image를 읽고 write한 후 bootscript 삭제
$ vi myboot0.cmd
setenv upgrade_read fatload mmc 2:1 ${loadaddr} core-lora-image-imx6sxsabresd.wic 
setenv upgrade_write mmc write 0x82400000 0xE000 0x6CCF8‬ 
setenv upgrade_remove fatrm mmc 2:1 ${script}
setenv upgradelog_start         echo ======== Simple Upgrade Script
setenv upgradelog_success       echo ======== Succeed to upgrade the firmware
setenv upgradelog_success_read  echo ======== Succeed to read the firmware
setenv upgradelog_success_write echo ======== Succeed to wirte the firmware
setenv upgradelog_fail_read     echo ======== Failed to read a firmware file 
setenv upgradelog_fail_write    echo ======== Failed to write a firmware file 
setenv upgrade_targets read write remove 
setenv upgrade_loop "for target in ${upgrade_targets}; do run upgrade_${target}; done" 
setenv upgrade_select "run upgradelog_start; if run upgrade_read; then if run upgrade_write; then run upgrade_remove; else run upgradelog_fail_write; fi; else run upgradelog_fail_read; fi"
run upgrade_select


  • 전체순차적으로 실행 
SDcard 삽입시 계속 Loop에 지속적으로 실행되며, SD Card 제거시 동작 중지
$ vi myboot1.cmd
echo ======== Simple Version Upgrade Script;
setenv targetaddr ${loadaddr};
if test $version = 1; then
   echo "======== checked your firmware version";
   setenv upgrade_read fatload mmc 2:1 ${loadaddr} core-lora-image-imx6sxsabresd.wic
   setenv upgrade_write mmc write 0x82400000 0xE000 0x6CCF8
   if run upgrade_read; then
      echo "======== Ok found a SD card upgrade file";
      echo "======== Start to upgrade a firmware";

      if run upgrade_write; then
         echo "======== Ok write the firmware into eMMC";
         setenv version 2; 
         mw  ${targetaddr} 0 100;
         mw  ${targetaddr} 0x43435553 1;
         setexpr targetaddr $targetaddr + 4;
         mw  ${targetaddr} 0x20535345 1;
         fatwrite mmc 2:1 ${loadaddr} result.txt 8         
      else
         echo "======== failed to write the image to eMMC";
         mw  ${targetaddr} 0 100;
         mw  ${targetaddr} 0x4c494146 1;
         setexpr targetaddr $targetaddr + 4;
         mw  ${targetaddr} 0x20 1;
         fatwrite mmc 2:1 ${loadaddr} result.txt
         setenv version 0
      fi
   else
      echo "======== failed to read the image from SD card";
      mw  ${targetaddr} 0 100;
      mw  ${targetaddr} 0x4c494146 1;
      setexpr targetaddr $targetaddr + 4;
      mw  ${targetaddr} 0x20 1;
      setenv version 0;
   fi
else
   echo "======== its same version";
   mw  ${targetaddr} 0 100;
   mw  ${targetaddr} 0x454d4153 1;
   setexpr targetaddr $targetaddr + 4;
   mw  ${targetaddr} 0x52455620 1;
   setexpr targetaddr $targetaddr + 4;
   mw  ${targetaddr} 0x4e4f4953 1;
   fatwrite mmc 2:1 ${loadaddr} result.txt
fi
saveenv;
reset;
boot script example
  https://boundarydevices.com/boot-scripts-for-main-line-u-boot-on-i-mx6/


  • boot scirpt 생성

아래와 같이 기본이 PowerPC로 되어있으므로, 가능하다면, ARM으로 변경해서 사용하자. (아래와 같이 사용해도 동작가능)

$ mkimage -T script -C none -n 'Uboot Script File' -d myboot0.cmd boot.scr
Image Name:   Uboot Script File
Created:      Fri May 15 17:00:50 2020
Image Type:   PowerPC Linux Script (uncompressed)
Data Size:    271 Bytes = 0.26 kB = 0.00 MB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 263 Bytes = 0.26 kB = 0.00 MB


$ mkimage -T script -C none -n 'Uboot Script File' -d myboot1.cmd boot.scr
Image Name:   Uboot Script File
Created:      Mon May 18 10:56:40 2020
Image Type:   PowerPC Linux Script (uncompressed)
Data Size:    979 Bytes = 0.96 kB = 0.00 MB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 971 Bytes = 0.95 kB = 0.00 MB


  • boot script 적용

=> setenv version 1 // version 입력
=> setenv loadbootscript fatload mmc 2:1 ${loadaddr} ${script}; // SD Card Read로 변경 
=> saveenv
=> reset

setenv loadbootscript fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};

  https://www.denx.de/wiki/view/DULG/UBootScripts

이를 이용하여 간단히 Upgrade script 도 간단히 만들수 있다.

4/29/2018

Raspberry Pi 의 Device Tree 및 cmdline 수정

1. Raspberry Pi Booting 및 설정 분석

  • Raspberry Pi Boot관련정보 
  1. cmdline.txt : kernel cmdline 수정가능 
  2. config.txt : Raspberry 설정 파일 
  3. bootcode.bin : Raspberry bootloader로 SoC에의해 Loading 되고 start*.elf를 로딩
  4. start.elf, start_x.elf, start_db.elf, start_cd.elf : firmware로 사용되지만 elf파일형식 
  5. fixup.dat, fixup_x.dat, fixup_db.dat, fixup_cd.dat : start*.elf의 linker file 
  6. *.dtb : Device Tree Blob

  https://wikidocs.net/3198
  https://wikidocs.net/18317


1.1 /boot 파일 확인 

일단 아래를 보면, dtb 파일과 kernel.img가 많아서 현재 사용중인 이미지를 알아야겠다.
추측을 하면 아래의 것을 사용할 것으로 짐작

$ cd /boot
bcm2708-rpi-0-w.dtb     bcm2709-rpi-2-b.dtb       bootcode.bin   fixup_cd.dat  issue.txt         LICENSE.oracle  start.elf
bcm2708-rpi-b.dtb       bcm2710-rpi-3-b.dtb       cmdline.txt    fixup.dat     kernel7.img       overlays        start_x.elf
bcm2708-rpi-b-plus.dtb  bcm2710-rpi-3-b-plus.dtb  config.txt     fixup_db.dat  kernel.img        start_cd.elf
bcm2708-rpi-cm.dtb      bcm2710-rpi-cm3.dtb       COPYING.linux  fixup_x.dat   LICENCE.broadcom  start_db.elf


1.2 DTS 와 DTB 구조 복습 (Device Tree) 

Device Tree 의 기본이해 (관련예제도 링크)
  https://ahyuo79.blogspot.com/2015/08/kernel-boot-kernel-device-tree.html
  https://www.elinux.org/images/a/ad/Arm-soc-checklist.pdf

Device Tree Spec (v0.2 와 v0.1) 및 각 문법 이해 (필독)
  https://www.devicetree.org/specifications/
  https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.2
  https://github.com/devicetree-org/devicetree-specification/releases/tag/v0.1

Device Tree 활용
  https://elinux.org/Device_Tree_Usage


  • DTS의 기본구조 
/ 로 시작하여 model과 아래 좌측을 부터 정의하기 시작하여 구성

  • 상위기본구성 분석
  1. / 의 model= MACHINE 정보이름과 compatibale 에 해당 arch를 선택 (MACHINE 정보)
  2.  #address-cells 1 , #size-cells  1 의 의미는 
    1. child의 address cell u32 갯수와 size cell u32 갯수 말하며 이는 reg에 적용 
  3. memory@0 의 의미는 memory address 0 의미 
    1. reg = <0  0x20000000) address 와 size 
  4. uart@fe00100 의 의미는 uart 의 address는 0xfe00100 
    1. reg = <0xfe001000 0x100 > 은 address 와 size 



  • Sample DTS (Deivce Tree Syntax) 구조 (상위 Spec 문서참조)
아래와 같이 DTS도 Version 이 존재하며, 각 Version 별로 문법이 변경될 것이므로 이부분을 반드시 확인
C와 같이 Preprocessor가 먼저 진행 빌드되므로 이점 주의 
$ vi arch/arm/boot/dts/mysample.dts  //kernel or uboot 
/dts-v1/;  // device tree spec 를 반드시 참조하며, 각 node의 manual 별도로 보자 

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>

//커널의  ./include/dt-bindings/  
//커널의 ./scripts/dtc/include-prefixes/dt-bindings    
// dtc는 ./scripts/dtc 에 존재 

#include "sample.dtsi"


// 아래와 같이 C처럼 Preprocess(상위 include)가 동작가능하며, 주석도 /**/ // 둘다 가능

#define TEST  //preprocess 도 동작가능 C처럼 Preprocess가 다른 것 보다 먼저 실행되는 것을 주의  

#if 1 // jhlee 

#endif

#ifndef TEST

#endif

#ifdef TEST

#endif

#if defined(TEST) //jhlee

#else //orgin

#endif




/ {   // / { 는 DTS Main을 의미하며, 만약 sample.dtsi 이 것이 포함이 되어 있다면, 그곳에 위치에 들어간다고 생각하면됨

//보통 Kernel에서 model 에 정보를 넣으면, 부팅시 Machine Name 확인가능 
//조금 고급스럽게 하고자 하면 색 정보도 같이 넣어 만들자  
//sample.dtsi 이미 있지만, 중복으로 넣어 최종이것으로 빌드하면 최종값으로 적용가능  
        //model = "fsl,mpc8572da";     
        //MACHINE 정보 Name이며 마음대로 변경,DT_MACHINE_START (Device Tree용) or MACHINE_START         
        model = "EVM_JHLEE";       
        compatible = "fsl,mpc8572da";       //board 호환성이며, "manufacturer,model" kernel 검색 
};
// }; 는 상위 model 때문에 삽입 

#if 1 //아래 다시 중복설정할 경우 이것이 최종 값으로 결정되며, model만 재선언 (제조사 생략)하여, 내맘대로 변경    
/ {
      // Kernel Boot시 색깔까지 넣어 표시   
      model = "\x1b[1m \x1b[93m  Jeonghun Board Ver 0.0 \x1b[0m"; // Machin Name을 변경      
};
#endif 

// 주석 
/* 주석 */


/* 
보통 gpio node가 구성되고, PINMUX에서 GPIO로 설정하면, User에서 /sys/class/gpio/export 를 이용하여 직접사용가능 
GPIO4_18  보통 (4-1)*32+18 = 114  
GPIO4_19  보통 (4-1)*32+18 = 115
*/
/*
 /sys/class/gpio/export 
 /sys/class/gpio/gpio114/direction
 https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
 항상 compatible 에서 device driver와 연결하므로, Kernel에서 Pinmux를 하였다고, 자동으로 /sys/class/gpio/export에 적용되지 않는다 
 */ 

  • 필요없는 부분 중복된 부분삭제 관련예제
  1. /delete-node/      : node or lable 삭제
  2. /delete-property/ : node 의 property 삭제
  3. /omit-if-no-ref/    : dtc에게 사용하지 않는다면, 삭제 
  https://elinux.org/Device_Tree_Source_Undocumented

상위에서 설명했듯이 중복많이 허용하며, 최종선언된 dts기준으로 파싱을 시작하기때문에 필요없다면, 
나만의 dts를 만들경우 최종 dts include하고 필요없는 것을 정리하도록하자  

// 이미 이전에 선언된 uart1 label 의 property의 status를 okay ->disabled 변경 
&uart1 {
   status = "disabled";
};

// 이미 이전에 선언된 uart1 lalel 의 특정 property만 삭제 
&uart1 {
    /delete-property/ fsl,uart-has-rtscts;
};


/* 

node의 구성 은 보통 label: node로  or node로만 구성될 수가 있으며, label에는 &를 사용 

label: node  

adv_bridge0: adv7535@3d {
...
};

adv_bridge1: adv7535@3d {
...
};
*/
 

// node를 삭제방법은 label에는 &사용하며, node 를 직접입력할 경우 &불필요

/delete-node/ &adv_bridge0;
/delete-node/ &adv_bridge1;

  • OS에서는 호환성목적으로 aliases 기능을 사용
각 Chip label 이름이 다 다르게 정의될 수 있으므로, OS가 알수 있도록 이를 변경 
// aliases는 node의 새로 naming 하여 쉽게 node구성하며, 주로 OS 즉 linux 호환성을위해서 사용해준다  
// 구성은 이전과 같이 label에 &사용
aliases {
     rtc0 = &snvsrtc;
     rtc1 = &rtc;
};


chosen {
      bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

https://elinux.org/Device_Tree_Usage#aliases_Node

  • #xxx-cells 의 의미 
child의 cells 의 갯수를 정의해주는 것으로 기본적인 address-cells 과 size-cells 이 존재한다.
더불어 다양한 #로 시작하는 cells들이 존재 
/dts-v1/;

/ {
    #address-cells = <1>; // address-cells의 의미 child의 reg의 address u32 갯수  
    #size-cells = <1>;    // size-cells 의 의미 child의 reg의 size u32 갯수  

    ...

    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >; // 상위 address-cells 수(1) 와 size-cells 수(1)로 결정
    };

    serial@101f2000 {
        compatible = "arm,pl011";
        reg = <0x101f2000 0x1000 >;
    };

    gpio@101f3000 {
        compatible = "arm,pl061";
        reg = <0x101f3000 0x1000
               0x101f4000 0x0010>; // 상위 address-cells 수(1) 와 size-cells 수(1)로 결정 연속 2개 
    };

    interrupt-controller@10140000 {
        compatible = "arm,pl190";
        reg = <0x10140000 0x1000 >;
    };

    spi@10115000 {
        compatible = "arm,pl022";
        reg = <0x10115000 0x1000 >;
    };

    ...

https://elinux.org/Device_Tree_Usage#Memory_Mapped_Devices
};

  • range 의 의미 
OS는 virtual address를 사용하며, 이를 위해서 memory map-io로 연결하여 사용한다. 
이때 각 영역의 부분의 정의해주는 것이 range의 기능이다. 
/dts-v1/;

/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;  //parent의 reg의 address u32 수  
    #size-cells = <1>     //parent의 reg의 size u32 수  
    ...
    external-bus {
        #address-cells = <2>;  //child의 reg의 address u32 수  
        #size-cells = <1>;     //child의 reg의 size u32 수  
 
/*
range(Address Translation) 는 address translation을 위한 list 구성 
   1. the child's #address-cells value(2),  
   2. the parent's #address-cells value(1), 
   3. the child's #size-cells(1) 
마지막 size로 memory map을 하여 영역 넣어구성 아래와 같이 mapping 

- Offset 0 from chip select 0 is mapped to address range 0x10100000 - 0x1010ffff
- Offset 0 from chip select 1 is mapped to address range 0x10160000 - 0x1016ffff
- Offset 0 from chip select 2 is mapped to address range 0x30000000 - 0x30ffffff

*/
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash

        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;  // 상위 child address 2개 와 size 1  
        };

        i2c@1,0 {
            compatible = "acme,a1234-i2c-bus";
            #address-cells = <1>; // node child address u32 수  
            #size-cells = <0>;    // node child reg의 e u32 수  
            reg = <1 0 0x1000>;   // 상위 child address  2개 와 size 1  
            rtc@58 {
                compatible = "maxim,ds1338";
                reg = <58>;             //상위 node child (1,0) 
            };
        };

        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};
https://elinux.org/Device_Tree_Usage#Ranges_.28Address_Translation.29
https://elinux.org/Device_Tree_Usage#PCI_Host_Bridge
https://elinux.org/Device_Tree_Usage#How_Interrupts_Work



Kernel GPIO 기본사용법
  https://www.kernel.org/doc/Documentation/gpio/gpio-legacy.txt

  • Device Tree 관련문서
Device Tree는 현재 각 Platform Device Driver마다 각각의 설정값들이 존재하는데, 관련부분을 아래에서 검색해서 찾자
  https://www.kernel.org/doc/Documentation/devicetree/bindings/

  • DTB (Flattened Device Tree 라고 불림) 의 구조 





1.3 Device Tree 비교 및 확인 

Raspberry Pi에 dtc 설치 되었는지 확인

  • 사용중인 Device Tree를 확인
/proc/device-tree 정보를 dtc를 이용하여 dts 파일생성방법, 역으로 생성했기때문에 원래사용하던 dts와는 완전동일할 수는 없다.

$ dtc -I fs -O dts -o current.dts /proc/device-tree/ 

  • DTB To DTS로 변경 
dtb 파일을 dts 파일로 역으로 변경했으므로, 상위와 같이 원래 dts와 완전동일할 수가 없음

$ sudo dtc -I dtb -O dts -o bcm2710-rpi-3-b-plus.dts /boot/bcm2710-rpi-3-b-plus.dtb
$ sudo dtc -I dtb -O dts -o bcm2710-rpi-3-b.dts /boot/bcm2710-rpi-3-b.dtb
$ sudo dtc -I dtb -O dts -o bcm2708-rpi-b-plus.dts /boot/bcm2708-rpi-b-plus.dtb

  • DTS 비교 
사용 중인  DTS 상위 DTB 다르기 때문에 일단 상위 /boot의 dtb 사용을 의심.

$ diff -urN current.dts bcm2710-rpi-3-b-plus.dts 
--- current.dts 2019-02-18 23:34:57.966477519 +0900
+++ bcm2710-rpi-3-b-plus.dts 2019-02-18 23:36:18.841755013 +0900
@@ -1,1159 +1,941 @@
 /dts-v1/;
 
+/memreserve/ 0x0000000000000000 0x0000000000001000;
 / {
- compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
- serial-number = "000000003befb7f8";
- model = "Raspberry Pi 3 Model B Rev 1.2";
- memreserve = 0x3b400000 0x4c00000="";
+ compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837";
+ model = "Raspberry Pi 3 Model B+";

$ diff -urN current.dts bcm2710-rpi-3-b.dts 
--- current.dts 2019-02-18 23:34:57.966477519 +0900
+++ bcm2710-rpi-3-b.dts 2019-02-18 23:42:58.263596240 +0900
@@ -1,1159 +1,940 @@
 /dts-v1/;
 
+/memreserve/ 0x0000000000000000 0x0000000000001000;
 / {
  compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
- serial-number = "000000003befb7f8";
- model = "Raspberry Pi 3 Model B Rev 1.2";
- memreserve = <0x3b400000 0x4c00000="">;
+ model = "Raspberry Pi 3 Model B";
  interrupt-parent = <0x1>;
  #address-cells = <0x1>;
  #size-cells = <0x1>;

$ diff -urN current.dts bcm2708-rpi-b-plus.dts | head -n 30
--- current.dts 2019-02-18 23:34:57.966477519 +0900
+++ bcm2708-rpi-b-plus.dts 2019-02-18 23:51:14.696159160 +0900
@@ -1,1235 +1,1066 @@
 /dts-v1/;
 
+/memreserve/ 0x0000000000000000 0x0000000000001000;
 / {
- compatible = "raspberrypi,3-model-b", "brcm,bcm2837";
- serial-number = "000000003befb7f8";
- model = "Raspberry Pi 3 Model B Rev 1.2";
- memreserve = <0x3b400000 0x4c00000="">;
+ compatible = "brcm,bcm2835";
+ model = "Raspberry Pi Model B+";
  interrupt-parent = <0x1>;
  #address-cells = <0x1>;
  #size-cells = <0x1>;

  • bootcode 분석
현재 사용중인 Device Tree를 정확하게 잘 몰라 다른 bootloader 를 분석했지만, 역시나. grep을 이용하여 dtb를 찾으려해도 찾지를 못했다.

$ hd /boot/bootcode.bin 
...
0000c6e0  75 70 0a 00 46 61 69 6c  65 64 20 74 6f 20 69 6e  |up..Failed to in|
0000c6f0  69 74 69 61 6c 69 73 65  20 6c 69 6e 6b 0a 00 00  |itialise link...|
0000c700  49 6e 69 74 69 61 6c 69  73 65 20 68 75 62 0a 00  |Initialise hub..|
0000c710  46 6f 75 6e 64 20 25 64  20 70 6f 72 74 73 2c 20  |Found %d ports, |
0000c720  6d 75 6c 74 69 5f 74 74  20 3d 20 25 64 0a 00 53  |multi_tt = %d..S|
0000c730  65 74 74 69 6e 67 20 69  6e 74 65 72 66 61 63 65  |etting interface|
0000c740  20 25 64 0a 00 46 61 69  6c 65 64 20 74 6f 20 73  | %d..Failed to s|
0000c750  65 74 20 69 6e 74 65 72  66 61 63 65 20 25 64 0a  |et interface %d.|
0000c760  00 45 6e 61 62 6c 69 6e  67 20 50 4f 52 54 20 50  |.Enabling PORT P|
0000c770  4f 57 45 52 20 6f 6e 20  70 6f 72 74 20 25 64 0a  |OWER on port %d.|
0000c780  00 46 61 69 6c 65 64 20  74 6f 20 73 65 74 20 66  |.Failed to set f|
0000c790  65 61 74 75 72 65 20 48  55 42 5f 46 45 41 54 55  |eature HUB_FEATU|
0000c7a0  52 45 5f 50 4f 52 54 5f  50 4f 57 45 52 20 25 64  |RE_PORT_POWER %d|
0000c7b0  0a 00 57 61 69 74 69 6e  67 20 66 6f 72 20 64 65  |..Waiting for de|
0000c7c0  76 69 63 65 73 20 74 6f  20 72 65 73 70 6f 6e 64  |vices to respond|
0000c7d0  20 74 6f 20 72 65 73 65  74 0a 00 46 6f 75 6e 64  | to reset..Found|
0000c7e0  20 64 65 76 69 63 65 20  6f 6e 20 70 6f 72 74 20  | device on port |
0000c7f0  25 64 0a 00 46 6f 75 6e  64 20 68 69 67 68 73 70  |%d..Found highsp|
0000c800  65 65 64 20 64 65 76 69  63 65 0a 00 48 75 62 20  |eed device..Hub |
0000c810  64 65 76 69 63 65 20 66  6f 75 6e 64 20 61 74 20  |device found at |
0000c820  61 64 64 72 20 25 64 2c  20 65 6e 75 6d 65 72 61  |addr %d, enumera|
0000c830  74 69 6e 67 20 48 55 42  0a 00 44 65 76 69 63 65  |ting HUB..Device|
0000c840  20 66 6f 75 6e 64 3a 20  74 79 70 65 20 3d 20 25  | found: type = %|
0000c850  73 2c 20 61 64 64 72 20  3d 20 25 64 0a 00 4d 61  |s, addr = %d..Ma|
0000c860  73 73 20 73 74 6f 72 61  67 65 00 45 74 68 65 72  |ss storage.Ether|
0000c870  6e 65 74 20 61 64 61 70  74 65 72 00 49 67 6e 6f  |net adapter.Igno|
0000c880  72 69 6e 67 20 6c 6f 77  20 73 70 65 65 64 20 64  |ring low speed d|
0000c890  65 76 69 63 65 0a 00 44  65 76 69 63 65 20 66 61  |evice..Device fa|
0000c8a0  69 6c 65 64 20 74 6f 20  72 65 73 70 6f 6e 64 20  |iled to respond |
0000c8b0  74 6f 20 72 65 73 65 74  0a 00 00 00 79 00 00 00  |to reset....y...|
....

$ strings /boot/bootcode.bin | grep dtb

  • 제공하는 Kernel Image 분석 
/boot/kernel.img 와 kernel7.img는 아래와 같이 다르게 나오며, 압축때문인 것으로 생각이 된다.

$ cat /proc/version 
Linux version 4.14.34-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1110 SMP Mon Apr 16 15:18:51 BST 2018

$ hd /boot/kernel.img | grep 'Linux'

$ strings /boot/kernel.img | grep 'Linux'
Uncompressing Linux...

$ strings /boot/kernel7.img | grep 'Linux'
Uncompressing Linux...


uImage라고 한다면, 64 byte의 헤더를 버려야 하지만, 상위 이미지를 보면 uImage 구조와 다른 것 같다.
zImage라고 생각이 들어 아래와 같이 시도해본다.


uImage 구조체
  http://www.isysop.com/unpacking-and-repacking-u-boot-uimage-files/
  http://forum.falinux.com/zbxe/index.php?document_srl=564748&mid=lecture_tip

zImage 구조
  https://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/kernel-image-file-structure.html

zImage (LZMA)
  https://stackoverflow.com/questions/37672417/getting-kernel-version-from-the-compressed-kernel-image

GPIO
  https://www.kosagi.com/w/index.php?title=Definitive_GPIO_guide
  • 사용중인 Kernel 분석 
사용중인 Kernel은 잘 나온다. (압축이 되지 않았으니 잘나오는 것 같다)

$ sudo strings /dev/mem | grep 'Linux'   
....
Booting Linux on physical CPU 0x0
Linux version 4.14.34-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1110 SMP Mon Apr 16 15:18:51 BST 2018

8/14/2015

Uboot Script 이해 및 Device Tree Boot 설정 (Sitara)

1. Uboot Env 환경변수 

setenv or set : 명령이용하여 환경변수 설정가능 uboot에서 많은 환경변수를 제공하며, script기능도 제공

1.1 Uboot Hush Script 이해

환경변수 설정과 기본 script 실행하는 방법은 아래와 같으며, Uboot에서 사용하는 Command는 Uboot 빌드시 CONFIG 옵션에 따라
변경되기 때문에 차이는 있지만, 기본 Command들은 대체적으로 알아두자.

  • UBoot의 기본 env 와 command 이해 
  1. bootcmd:  uboot가 기본적으로 실행되는 변수 (가장중요)
  2. 이외에 암묵적으로 많이 사용하는 환경변수가 존재 (stdin,stdout, 등 ) 
  3. script의 기본은 uboot cmd의 나열로 구성하고 환경변수 및 구분자를 세미콜론사용
  4. run을 이용하여 만들어진 script을 실행가능 
  5. setenv 이용하여 환경변수 및 script 생성  

  • UBoot Script 의 확장이해 
  1. if <list>; then <command list>; [elif <list>; then <list>; ] [else <list>; then <list>;]
  2. while <list>; do <list>; done
  3. until <list>; do <list>; done
  4. for <name> in <word list>; do <list> ; done

1,2,3 앞에 test command를 이용하여 비교가 가능하며,  뒤에 는 script or 환경변수를 넣으면 된다.   

  http://www.compulab.co.il/utilite-computer/wiki/index.php/U-Boot_Scripts

1.2 Uboot Hush Script 의 예제 

위에서 확장으로 사용되는 예제들을 한번 살펴보자.

  • Uboot Script  if 문 test 예제 
test command를 이용하여 비교하고, 그 결과을 적용

findfdt=if test $board_name = AM43EPOS; then setenv fdtfile am43x-epos-evm.dtb; fi; if test $board_name = AM43__GP; then setenv fdtfile am437x-gp-evm.dtb; fi; if test $board_name = AM43__SK; then setenv fdtfile am437x-sk-evm.dtb; fi; if test $fdtfile = undefined; then echo WARNING: Could not determine device tree; fi; // if문 예제 

  • Uboot Script for 문 예제 
boot_target 이라는 word_list에서 target이라는 변수를 만들어 반복문을 만들어 여러 bootcmd_target을 실행한다.

boot_targets=mmc0 legacy_mmc0 mmc1 legacy_mmc1 nand0 pxe dhcp    // target list 
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done  //for boot_targets에서 환경변수에서 target을 추출하여 bootcmd_x 실행
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi
bootcmd_legacy_mmc0=setenv mmcdev 0; setenv bootpart 0:2 ; run mmcboot
bootcmd_legacy_mmc1=setenv mmcdev 1; setenv bootpart 1:2 ; run mmcboot
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_nand=run nandboot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi

uboot script은 쉽게 이해가능하며, 누구나 쉽게 사용가능.


1.3 외부 Uboot Script 사용방법

  • Uboot에서 Uboot Script 실행
Uboot에서 FAT에서 boot.scr를 읽어서 이를 source를 이용하여 실행하며, 보통 SDCard Boot를 했을 때 사용한다.

U-Boot# pri
...
script_addr=0x80900000
loadbootscript=fatload mmc 0 ${script_addr} boot.scr
bootscript= echo Running bootscript from MMC/SD to set the ENV...; source ${script_addr}
bootcmd=if mmc init; then if run loadbootscript; then run bootscript; else if run loaduimage; then run mmcboot; else run nandboot; f
i; fi; else run nandboot; fi
...

  • 외부 Uboot Script 생성방법
$ vi boot-nfs.txt 
setenv bootargs 'console=ttyO0,115200n8 root=/dev/nfs nfsrootdebug rw rootdelay=10 mem=80M vram=4M notifyk.vpssm3_sva=0xBFD00000 nfsroot=192.168.1.100:/home/jhlee/dm8127/work/Source/ipnc_rdk/target/filesys,nolock eth=32:30:3a:63:64:3a ip=192.168.1.168 cmemk.phys_start=0x85000000 cmemk.phys_end=0x89000000 cmemk.allowOverlap=1 earlyprintk'

$ mkimage -A arm -T script -C none -d boot-nfs.txt  boot.scr // Uboot Script 생성

생성된 boot.scr를 FAT에 복사하여 실행가능하여 이외에도 상위의 if문을 비롯하여 다양한 연속적인 Uboot Script을 생성가능하다


  • mkimage 설치
Uboot안에 mkimage가 존재하지만, PATH설정를 비롯하여 귀찮아서 직접 설치
$ sudo apt-get install uboot-mkimage //mkimage가 없을 경우 설치 

  https://wiki.ubuntu.com/ARM/EditBootscr
  http://www.denx.de/wiki/DULG/UBootScripts

2. Uboot 와 Device Tree Boot 설정 

AM437x와 AM335x는 Uboot에서 손쉽게 Device Tree Boot를 설정변경이 가능하며,
이전에 Device Tree File에 대해서 설명했듯이 zImage와 dtb 파일은 filesystem의 /boot라는 곳에 저장이 되어있다.

Device Tree 관련내용
  https://ahyuo79.blogspot.com/2015/08/kernel-boot-kernel-device-tree.html

  • Uboot 와 Device Tree Boot 역할
각각의 File (zImage와 *.dtb) 들을  Load를 하면 Uboot Device Tree 기본역할은 한것이며, 이 관련 script을 수정을하면된다.


  • Device Tree Boot 설정 변경 (다양한 Kernel 및 Device Tree 선택)
Uboot Script or 환경변수 설정을 변경하여 이를 변경하자
특히 findfdt는 device tree의 file을 설정을 하는 것이며, findfdt 대신 직접 설정을 하여도 좋다.


2.1 Uboot의 boot 분석 (AM437x-EVM-GP)

이제 중요한 uboot에서 dtb을 찾고 zImage를 찾아 booting을 해보자
기본명령어는 다음과 같다

bootz ${loadaddr} - ${fdtaddr} 


FDT (Flattened Device Tree) 는  DTB (Device Tree Blob)를 말하며 관련 구조는 Device Tree Spec를 참조

  • Uboot Env MMC BOOT 분석 
  1. bootcmd : dtb를 찾아 설정 후 mmcboot / usbboot/ nand boot로 순차실행
  2. findfdt : 현재 board_name에 따라 fdtfile 에 dtb 파일설정
  3. mmcboot: mmc device를 설정하고 rescan 
  4. mmcboot: uEnv.txt (uboot Env) File이 존재한다면 찾아 설정 
  5. mmcboot: importenv는 외부에 존재 할 경우,  uenvcmd는 존재할 경우 동작  두부분 생략
  6. mmcboot: loadimage로 kernel을  load_addr로 load 한다 ( File system의 /boot) 
  7. mmcboot: loadfdt로 dtb file을 fdt_addr로 load한다   (File system의 /boot)
  8. mmcboot: mmcargs로 kernel argument 설정
  9. mmcboot: bootz ${loadaddr} - ${fdtaddr} 로 kernel과 dtb booting  


U-Boot# pri
arch=arm
baudrate=115200
board=am43xx
board_name=AM43__GP
board_rev=1.4A
bootcmd=run findfdt; run mmcboot;run usbboot;run nandboot; 
bootdelay=1
bootdir=/boot
bootenv=uEnv.txt
bootfile=zImage
bootm_size=0x10000000
bootpart=0:2
console=ttyO0,115200n8
cpu=armv7
dfu_alt_info_emmc=MLO raw 0x100 0x100 mmcpart 0;u-boot.img raw 0x300 0x1000 mmcpart 0
dfu_alt_info_mmc=boot part 0 1;rootfs part 0 2;MLO fat 0 1;spl-os-args fat 0 1;spl-os-image fat 0 1;u-boot.img fat 0 1;uEnv.txt fat 0 1
dfu_alt_info_ram=kernel ram 0x80200000 0x4000000;fdt ram 0x80f80000 0x80000;ramdisk ram 0x81000000 0x4000000
dfu_bufsiz=0x10000
eth1addr=34:b1:f7:30:fb:00
ethact=cpsw
ethaddr=34:b1:f7:30:f7:fe
fdt_addr_r=0x88000000
fdtaddr=0x88000000
fdtfile=undefined
findfdt=if test $board_name = AM43EPOS; then setenv fdtfile am43x-epos-evm.dtb; fi; if test $board_name = AM43__GP; then setenv fdtfile am437x-gp-evm.dtb; fi; if test $board_name = AM43__SK; then setenv fdtfile am437x-sk-evm.dtb; fi; if test $fdtfile = undefined; then echo WARNING: Could not determine device tree; fi; 
importbootenv=echo Importing environment from mmc ...; env import -t $loadaddr $filesize
kernel_addr_r=0x82000000
loadaddr=0x82000000
loadbootenv=load ${devtype} ${devnum} ${loadaddr} ${bootenv}
loadfdt=load ${devtype} ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
loadimage=load ${devtype} ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
loadramdisk=load ${devtype} ${devnum} ${rdaddr} ramdisk.gz
mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype}
mmcboot=mmc dev ${mmcdev}; setenv devnum ${mmcdev}; setenv devtype mmc; if mmc rescan; then echo SD/MMC found on device ${devnum};if run loadbootenv; then echo Loaded environment from ${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;if run loadimage; then run loadfdt; echo Booting from mmc${mmcdev} ...; run mmcargs; bootz ${loadaddr} - ${fdtaddr}; fi;fi;
mmcdev=0
mmcroot=/dev/mmcblk0p2 rw
mmcrootfstype=ext4 rootwait
mtdids=nand0=nand.0
mtdparts=mtdparts=nand.0:256k(NAND.SPL),256k(NAND.SPL.backup1),256k(NAND.SPL.backup2),256k(NAND.SPL.backup3),512k(NAND.u-boot-spl-os),1m(NAND.u-boot),256k(NAND.u-boot-env),256k(NAND.u-boot-env.backup1),7m(NAND.kernel),-(NAND.file-system)
nandargs=setenv bootargs console=${console} ${optargs} root=${nandroot} rootfstype=${nandrootfstype}
nandboot=echo Booting from nand ...; run nandargs; nand read ${fdtaddr} NAND.u-boot-spl-os; nand read ${loadaddr} NAND.kernel; bootz ${loadaddr} - ${fdtaddr}
nandroot=ubi0:rootfs rw ubi.mtd=NAND.file-system,4096
nandrootfstype=ubifs rootwait=1
netargs=setenv bootargs console=${console} ${optargs} root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw ip=dhcp
netboot=echo Booting from network ...; setenv autoload no; dhcp; tftp ${loadaddr} ${bootfile}; tftp ${fdtaddr} ${fdtfile}; run netargs; bootz ${loadaddr} - ${fdtaddr}
nfsopts=nolock
partitions=uuid_disk=${uuid_gpt_disk};name=rootfs,start=2MiB,size=-,uuid=${uuid_gpt_rootfs}
ramargs=setenv bootargs console=${console} ${optargs} root=${ramroot} rootfstype=${ramrootfstype}
ramdisk_addr_r=0x88080000
ramroot=/dev/ram0 rw
ramrootfstype=ext2
rdaddr=0x88080000
rootpath=/export/rootfs
soc=am33xx
static_ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off
stderr=serial
stdin=serial
stdout=serial
usbargs=setenv bootargs console=${console} ${optargs} root=${usbroot} rootfstype=${usbrootfstype}
usbboot=setenv devnum ${usbdev}; setenv devtype usb; usb start ${usbdev}; if usb dev ${usbdev}; then if run loadbootenv; then echo Loaded environment from ${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;if run loadimage; then run loadfdt; echo Booting from usb ${usbdev}...; run usbargs;bootz ${loadaddr} - ${fdtaddr}; fi;fi;usb stop ${usbdev};
usbdev=0
usbnet_devaddr=34:b1:f7:30:fb:00
usbroot=/dev/sda2 rw
usbrootfstype=ext4 rootwait
vendor=ti
ver=U-Boot 2014.07-gfb6ab76 (Jul 06 2015 - 16:10:49)

Environment size: 4128/65532 bytes 

  • Uboot Env ( NFS - Network 고정 IP Mode)
현재 dhcp를 사용하며 ip가 바뀌어서 고정 ip로 변경하기로 결정.
만약 AP에서 dhcp 세부설정이 가능하다면 위와 같이 사용.

setenv ipaddr '192.168.1.101'
setenv serverip '192.168.1.100'
setenv netmask '255.255.255.0'
setenv rootpath '/home/jhlee/am437x/targetNFS'
setenv netargs 'setenv bootargs console=${console} ${optargs} root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw ip=${ipaddr}' 
setenv netboot1 'echo Booting from network ...; setenv autoload no; tftp ${loadaddr} ${bootfile}; tftp ${fdtaddr} ${fdtfile}; run netargs; bootz ${loadaddr} - ${fdtaddr}'

setenv bootcmd 'run findfdt; run netboot1;'
setenv bootfile 'zImage'
setenv fdtfile 'am437x-gp-evm.dtb'  //직접 설정 후 run findfdt를 삭제가능 


Linux server의 /tftpboot에 bootfile과 fdtfile을 보관해야한다.


2.2 Uboot Env 분석 (AM335x SK, Start Kit )

AM437x와 거의 동일하며 UBOOT에서  zImage와 *.dtb을 변경을 해주면된다.

  • Device Tree Booting Command
bootz ${loadaddr} - ${fdtaddr} 


  • Uboot Env 분석 
=>pri
arch=arm
args_fit=setenv bootargs console=${console} 
args_mmc=run finduuid;setenv bootargs console=${console} ${optargs} root=PARTUUID=${uuid} rw rootfstype=${mmcrootfstype}
baudrate=115200
board=am335x
board_name=A335X_SK
board_rev=1.2B
board_serial=34124P192908
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootarm.efi; if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};elsebootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_fdt=try
boot_fit=0
boot_net_usb_start=usb start
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=mmc0 legacy_mmc0 mmc1 legacy_mmc1 nand0 pxe dhcp 
bootcmd=if test ${boot_fit} -eq 1; then run update_to_fit;fi;run findfdt; run init_console; run envboot; run distro_bootcmd
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi
bootcmd_legacy_mmc0=setenv mmcdev 0; setenv bootpart 0:2 ; run mmcboot
bootcmd_legacy_mmc1=setenv mmcdev 1; setenv bootpart 1:2 ; run mmcboot
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_nand=run nandboot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcount=4
bootdelay=2
bootdir=/boot
bootenvfile=uEnv.txt
bootfile=zImage
bootm_size=0x10000000
bootpart=0:2
bootscript=echo Running bootscript from mmc${mmcdev} ...; source ${loadaddr}
console=ttyO0,115200n8
cpu=armv7
dfu_alt_info_emmc=rawemmc raw 0 3751936
dfu_alt_info_mmc=boot part 0 1;rootfs part 0 2;MLO fat 0 1;MLO.raw raw 0x100 0x100;u-boot.img.raw raw 0x300 0x400;spl-os-args.raw raw 0x80 0x80;spl-os-image.raw raw 0x900 0x2000;spl-os-args fat 0 1;spl-os-image fat 0 1;u-boot.img fat 0 1;uEnv.txt fat 0 1
dfu_alt_info_nand=SPL part 0 1;SPL.backup1 part 0 2;SPL.backup2 part 0 3;SPL.backup3 part 0 4;u-boot part 0 5;u-boot-spl-os part 0 6;kernel part 0 8;rootfs part 0 9
dfu_alt_info_ram=kernel ram 0x80200000 0xD80000;fdt ram 0x80F80000 0x80000;ramdisk ram 0x81000000 0x4000000
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
envboot=mmc dev ${mmcdev}; if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadbootscript; then run bootscript;else if run loadbootenv; then echo Loaded env from ${bootenvfile};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;fi;fi;
eth1addr=d4:94:a1:86:70:e1
ethaddr=d4:94:a1:86:70:e0
fdt_addr_r=0x88000000
fdtaddr=0x88000000
fdtcontroladdr=8ef282f8
fdtfile=undefined
findfdt=if test $board_name = A335BONE; then setenv fdtfile am335x-bone.dtb; fi; if test $board_name = A335BNLT; then setenv fdtfile am335x-boneblack.dtb; fi; if test $board_name = BBG1; then setenv fdtfile am335x-bonegreen.dtb; fi; if test $board_name = A33515BB; then setenv fdtfile am335x-evm.dtb; fi; if test $board_name = A335X_SK; then setenv fdtfile am335x-evmsk.dtb; fi; if test $board_name = A335_ICE; then setenv fdtfile am335x-icev2.dtb; fi; if test $fdtfile = undefined; then echo WARNING: Could not determine device tree to use; fi; 
finduuid=part uuid mmc ${bootpart} uuid
fit_bootfile=fitImage.itb
fit_loadaddr=0x88000000
importbootenv=echo Importing environment from mmc${mmcdev} ...; env import -t ${loadaddr} ${filesize}
init_console=if test $board_name = A335_ICE; then setenv console ttyO3,115200n8;else setenv console ttyO0,115200n8;fi;
kernel_addr_r=0x82000000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0x82000000
loadbootenv=fatload mmc ${mmcdev} ${loadaddr} ${bootenvfile}
loadbootscript=load mmc ${mmcdev} ${loadaddr} boot.scr
loadfdt=load ${devtype} ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
loadfit=run args_fit; bootm ${loadaddr}#${fdtfile};
loadimage=load ${devtype} ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
loadramdisk=load mmc ${mmcdev} ${rdaddr} ramdisk.gz
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
mmcboot=mmc dev ${mmcdev}; setenv devnum ${mmcdev}; setenv devtype mmc; if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadimage; then if test ${boot_fit} -eq 1; then run loadfit; else run mmcloados;fi;fi;fi;
mmcdev=0
mmcloados=run args_mmc; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
mmcrootfstype=ext4 rootwait
mtdids=nand0=nand.0
mtdparts=mtdparts=nand.0:128k(NAND.SPL),128k(NAND.SPL.backup1),128k(NAND.SPL.backup2),128k(NAND.SPL.backup3),256k(NAND.u-boot-spl-os),1m(NAND.u-boot),128k(NAND.u-boot-env),128k(NAND.u-boot-env.backup1),8m(NAND.kernel),-(NAND.file-system)
nandargs=setenv bootargs console=${console} ${optargs} root=${nandroot} rootfstype=${nandrootfstype}
nandboot=echo Booting from nand ...; run nandargs; nand read ${fdtaddr} NAND.u-boot-spl-os; nand read ${loadaddr} NAND.kernel; bootz ${loadaddr} - ${fdtaddr}
nandroot=ubi0:rootfs rw ubi.mtd=NAND.file-system,2048
nandrootfstype=ubifs rootwait=1
netargs=setenv bootargs console=${console} ${optargs} root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw ip=dhcp
netboot=echo Booting from network ...; setenv autoload no; dhcp; run netloadimage; run netloadfdt; run netargs; bootz ${loadaddr} - ${fdtaddr}
netloadfdt=tftp ${fdtaddr} ${fdtfile}
netloadimage=tftp ${loadaddr} ${bootfile}
nfsopts=nolock
partitions=uuid_disk=${uuid_gpt_disk};name=rootfs,start=2MiB,size=-,uuid=${uuid_gpt_rootfs}
pxefile_addr_r=0x80100000
ramargs=setenv bootargs console=${console} ${optargs} root=${ramroot} rootfstype=${ramrootfstype}
ramboot=echo Booting from ramdisk ...; run ramargs; bootz ${loadaddr} ${rdaddr} ${fdtaddr}
ramdisk_addr_r=0x88080000
ramroot=/dev/ram0 rw
ramrootfstype=ext2
rdaddr=0x88080000
rootpath=/export/rootfs
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; if test -z "${fdtfile}" -a -n "${soc}"; then setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; fi; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootarm.efi; then echo Found EFI removable media binary efi/boot/bootarm.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x80000000
soc=am33xx
spiargs=setenv bootargs console=${console} ${optargs} root=${spiroot} rootfstype=${spirootfstype}
spiboot=echo Booting from spi ...; run spiargs; sf probe ${spibusno}:0; sf read ${loadaddr} ${spisrcaddr} ${spiimgsize}; bootz ${loadaddr}
spibusno=0
spiimgsize=0x362000
spiroot=/dev/mtdblock4 rw
spirootfstype=jffs2
spisrcaddr=0xe0000
static_ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off
stderr=serial@44e09000
stdin=serial@44e09000
stdout=serial@44e09000
update_to_fit=setenv loadaddr ${fit_loadaddr}; setenv bootfile ${fit_bootfile}
usb_boot=usb start; if usb dev ${devnum}; then setenv devtype usb; run scan_dev_for_boot_part; fi
usbnet_devaddr=de:ad:be:ef:00:01
vendor=ti
ver=U-Boot 2016.05-g6c5519b6fc (Dec 14 2016 - 19:14:27 -0500)

Environment size: 8557/131068 bytes

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

    8/12/2015

    Device Tree 구조 및 구성 Sitara (AM437x)

    1. Device Tree Syntax 

    DTS의 전체구조도 에대해 간단히 알아보고 어떻게 수정을 해야할지를 알아보자.

    • am437x-gp-evm-dts 전체구조 및 수정방법

    dtsi를 이용하여 참조하여 구성되며, 최종 dts file은 AM437x-gp-evm.dts 이며, 이는 dtc를 이용하여 dtb로 변환이 된다.


    • 본인이 별도로 DTS 관련부분들을 수정하고 싶은 경우
    1. 상위 관련 DTSI 파일들과 DTS파일들을 직접 다 수정하는 방법
    2. 새로운 DTS 파일을 생성 후 기존 최종 DTS를 include를 이용하여 포함하고 수정을 진행 

    DTS는 DTS or DTSI를 참조를 하므로 표현중복을 허용하므로 HW표현이 중복 될 경우 마지막의 DTS 정보기반으로 DTB를 생성하므로
    상위 2번이 가능하다.

    예를들면, 이미 이전 DTS에서 설정이 중복되는 부분이 존재하더라도 마지막에 추가된 syntax가 최종적용되므로 최종 DTS에서 수정을하면된다.

    중복허용Kernel Config/ Uboot Config도 허용하므로, 필요한 부분만 나중에 추가해서 설정을 하면된다.

    1.1 dts의 기본문법 이해 


    /dts-v1/; 
    
    [memory reservations] 
    
    / { 
           [property definitions] 
           [child nodes] 
    };
    
    

    1. // or  /* */ 주석을 의미한다. C 문법과 동일
    2. #include  , 프리프로세서로 동작 C 문법과 동일 
    3. /include/ 사용시 뒤 dts를 포함시킨다고 한다. 

    각 address-cells or size-cell 기본문법이해
      http://devicetree.org/Device_Tree_Usage


    Kernel의 Documentation/devicetree를 참조하면 대부분의 이해가능.
    자세한 부분은 source와 datasheet를 참조해야한다.


    1.2 am4372.dtsi 의 기본분석 

    • 기본작업
    1. AM4372의 기본적인 device 선언
    2. 각 device들은 ocp안에 선언이 되고, address와 size만 할당.
    3. 각 device의 상태는 대부분 disable 유지.

    • gic
           *INTERRUPT 설정

           http://Documentation/devicetree/bindings/open-pic.txt

    • 전체구조
           *ARM과 OMAP의 기본구조

           http://Documentation/devicetree/bindings/arm/vexpress.txt
           http://lDocumentation/devicetree/bindings/arm/omap/

    • vpfe
           *EDMA을 사용하지 않고 자체 전용 DMA사용
           *VENC와 VPBE를 미지원 대신 SGX사용해야할 것 같음
           *DM81xx HDVICP지원, AM38xx HDVPSS지원,  AM432x는 미지원

           https://en.wikipedia.org/wiki/PowerVR
           http://processors.wiki.ti.com/index.php/DM816x_C6A816x_AM389x_Overview
    • edma
           *EDMA설정을 위해 datasheet에서 아래 사항을 필독
           *현재 EVENT 설정만 사용 (세부설정 변경 모색)

           TPTC(Third-Party Transfer Controller),
           TPCC(Third-Party Channel Controller0~2) : 10.2.1 관련내용
           CROSSBAR (10.3.20.2 Crossbar Mapped)

           http://Documentation/devicetree/bindings/dma/ti-edma.txt

    1.3 am43-clocks.dtsi 구조 

    Clock 구조는 간단하며, scrm_clocks (CONTROL_MODULE) 과 prcm_clocks(PRCM)
    2가지로 구분이 되며, 개별 deivce clock 설정한다.

    * datasheet와 함께 분석필요


    1.4 am4372-gp-evm.dts 구조

    • 주요작업 
    1. 기존의 status 변경 및 pinctrl 변경
    2. i2c (ov2659-camera, aic3105-audio) 및 uart 설정 
    3. lcd와 backlight, keypad 구조 선언
    4. sound 구조선언 (mcasp와 별도)
    5. power control도 같이 하기에 LDO도 같이 설정

    • btwilink (bluetooth)