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 도 간단히 만들수 있다.