3.1.1.5. SD, eMMC and USB

The commands for using SD cards, eMMC flash and USB mass storage devices (hard drives, flash drives, card readers, etc) are all very similar. The biggest difference is that on some hardware we may not be able to run U-Boot out of ROM from the storage device as it is unsupported. Once U-Boot is running however, any of these may be used for the kernel and the root filesystem.

Usually in all the platforms there will be two MMC instances of which one would be SD and the other would be eMMC. The index of them can vary from one class of platforms to the other. For a given platform, the device number (device num) can be found in the following way,

U-Boot# mmc list
sdhci@fa10000: 0 (eMMC)
sdhci@fa00000: 1 (SD)

3.1.1.5.1. Partitioning eMMC from U-Boot

The eMMC device typically ships without any partition table. We make use of the GPT support in U-Boot to write a GPT partition table to eMMC. In this case we need to use the uuidgen program on the host to create the UUIDs used for the disk and each partition.

$ uuidgen
...first uuid...
$ uuidgen
...second uuid...
U-Boot # printenv partitions
uuid_disk=${uuid_gpt_disk};name=rootfs,start=2MiB,size=-,uuid=${uuid_gpt_rootfs}
U-Boot # setenv uuid_gpt_disk ...first uuid...
U-Boot # setenv uuid_gpt_rootfs ...second uuid...
U-Boot # gpt write mmc <device num> ${partitions} /* <device num> is device index obtained from mmc list for eMMC */

A reset is required for the partition table to be visible.

3.1.1.5.2. Updating an SD card from a host PC

This section assume that you have created an SD card using the script “create-sdcard.sh” packaged inside the installer or have made a compatible layout by hand. In this case, you will need to copy the all the boot images (MLO and u-boot.img for 32-bit platforms, tiboot3.bin, sysfw.itb, tispl.bin, u-boot.img for K3 based platforms, except AM64x and J7200 in which sysfw.itb is already combined with tiboot3.bin) files to the boot partition. At this point, the card is now bootable in the SD card slot. We default to using /boot/${bootfile} on the rootfs partition and the device tree file loaded from /boot with the same name as in the kernel.

3.1.1.5.3. Updating an SD card or eMMC using DFU

To see the list of available places to write to (in DFU terms, altsettings) use the mmc part command to list the partitions on the MMC device and printenv dfu_alt_settings_mmc or dfu_alt_settings_emmc to see how they are mapped and exposed to dfu-util.

U-Boot# mmc part

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

Partition     Start Sector     Num Sectors     Type
    1                   63          144522       c Boot
    2               160650         1847475      83
    3              2024190         1815345      83
U-Boot# printenv dfu_alt_info_mmc
dfu_alt_info=boot part 0 1;rootfs part 0 2;MLO fat 0 1;u-boot.img fat 0 1;uEnv.txt fat 0 1"

Note

The above command mmc part lists the partitions in the current selected device. So, to list the partitions in eMMC or SD one needs to switch to the required device by using the command mmc dev <device num>.

This means that you can tell dfu-util to write anything to any of:

  • boot

  • rootfs

  • MLO

  • u-boot.img

  • uEnv.txt

And that the MLO, u-boot.img and uEnv.txt files are to be written to a FAT filesystem.

To start DFU on the target on the first MMC device:

U-Boot # setenv dfu_alt_info ${dfu_alt_info_mmc}
U-Boot # dfu 0 mmc 0

On boards like AM57x GP EVM or BeagleBoard x15, where the second USB instance is used as USB client, the dfu command becomes:

U-Boot # dfu 1 mmc 0

Then on the host PC to write MLO to an existing boot partition:

$ sudo dfu-util -D MLO -a MLO

On the host PC to overwrite the current boot partition contents with a new created on the host FAT filesystem image:

$ sudo dfu-util -D fat.img -a boot

3.1.1.5. Updating an SD card or eMMC with RAW writes

In some cases it is desirable to write MLO and u-boot.img as raw images to the MMC device rather than in a filesystem. eMMC requires this, for example. In that case, the following is how to program these files and not overwrite the partition table on the device. We assume that the files exist on a SD card. In addition you may wish to write a filesystem image to the device, so an example is also provided.

U-Boot # mmc dev 0
U-Boot # mmc rescan
U-Boot # mmc dev 1
U-Boot # fatload mmc 0 ${loadaddr} MLO
U-Boot # mmc write ${loadaddr} 0x100 0x100
U-Boot # mmc write ${loadaddr} 0x200 0x100
U-Boot # fatload mmc 0 ${loadaddr} u-boot.img
U-Boot # mmc write ${loadaddr} 0x300 0x400
U-Boot # fatload mmc 0 ${loadaddr} rootfs.ext4
U-Boot # mmc write ${loadaddr} 0x1000 ...rootfs.ext4 size in bytes divided by 512, in hex...

3.1.1.5.4. Booting Linux from SD card or eMMC

Within the default environment for each board that supports SD/MMC there is a boot command called mmcboot that will set the boot arguments correctly and start the kernel. In this case however, you must first run loaduimagefat or loaduimage to first load the kernel into memory. For the exact details of each use printenv on the mmcboot, loaduimagefat and loaduimage variables and then in turn printenv other sub-sections of the command. The most important variables here are mmcroot and mmcrootfstype.

3.1.1.5.5. Booting tiboot3.bin, tispl.bin and u-boot.img from eMMC boot partition (For K3 class of SoCs)

The K3 based processors support booting from the eMMC boot partition. The following commands can be used to download tiboot3.bin, tispl.bin and u-boot.img from an SD card and write them to the eMMC boot0 partition at respective addresses.

Note

By default, SDK chooses boot0 partition for eMMC boot (equivalently done using mmc partconf 0 1 1 1). Boot partition can also be switched from boot0 to boot1 by using mmc partconf 0 1 2 1. This enables booting from boot1 partition. Switch to boot1 partition using mmc dev 0 2 and follow regular eMMC write commands (seen below). On rebooting with regular eMMC dip switch settings, boot1 partition will be used.

=> mmc dev 0 1
=> fatload mmc 1 ${loadaddr} tiboot3.bin
=> mmc write ${loadaddr} 0x0 0x800
=> fatload mmc 1 ${loadaddr} tispl.bin
=> mmc write ${loadaddr} 0x800 0x1000
=> fatload mmc 1 ${loadaddr} u-boot.img
=> mmc write ${loadaddr} 0x1800 0x2000

For loading images from a FAT partition on a different media, replace mmc with the required media. For example, to load images from a FAT partition on a USB Storage device connected to the zeroth instance of usb,

=> fatload usb 0 ${loadaddr} <file name>

Note

USB instance in AM64 SoC is brought out using a USB 2.0 micro-AB port on the GP EVM. This port can be used in both host and device modes. By default in U-Boot, peripheral mode is supported. For accessing USB storage devices in U-Boot, dr_mode should be set to “host” in the U-Boot device tree file. The following diff shows the required changes to be done. On Starter Kit, USB instance in AM64 SoC is brought out using a USB 3.0 Type A port, so the mode is set to host by default and the following diff would not be required.

diff --git a/arch/arm/dts/k3-am642-evm-u-boot.dtsi b/arch/arm/dts/k3-am642-evm-u-boot.dtsi
index d066973f89f1..ff8afee09402 100644
--- a/arch/arm/dts/k3-am642-evm-u-boot.dtsi
+++ b/arch/arm/dts/k3-am642-evm-u-boot.dtsi
@@ -55,7 +55,7 @@
};

 &usb0 {
-       dr_mode="peripheral";
+       dr_mode="host";
        u-boot,dm-spl;
 };

To give the ROM access to the boot partition, the following commands must be used for the first time:

=> mmc partconf 0 1 1 1
=> mmc bootbus 0 2 0 0
  • eMMC layout:

           boot0 partition (8 MB)                        user partition
   0x0+----------------------------------+      0x0+-------------------------+
      |     tiboot3.bin (1 MB)           |         |                         |
 0x800+----------------------------------+         |                         |
      |       tispl.bin (2 MB)           |         |                         |
0x1800+----------------------------------+         |        rootfs           |
      |       u-boot.img (4 MB)          |         |                         |
0x3800+----------------------------------+         |                         |
      |      environment (128 KB)        |         |                         |
0x3900+----------------------------------+         |                         |
      |   backup environment (128 KB)    |         |                         |
0x3A00+----------------------------------+         +-------------------------+

To boot from UDA parition of eMMC. Please set following

=> mmc partconf 0 1 7 1
=> mmc bootbus 0 2 0 0

Enable warm reset

On eMMC devices, warm reset will not work if EXT_CSD[162] bit is unset since the reset input signal will be ignored. Warm reset is required to be enabled in order to the eMMC to be in a “clean state” on power on reset so that ROM can do clean enumeration.

To set the EXT_CSD[162] bit, stop at U-boot prompt and execute the following command:

=> mmc rst-function 0 1

Warning

WARNING : This is a write-once field.

For more information, please refer to the latest U-boot documentation: https://docs.u-boot.org/en/latest/usage/cmd/mmc.html.


Boot kernel from eMMC

Note

rootfs is written to the user partition. The user partition is first required to be formatted as a ext4 file system and then the rootfs has to be written. It is not possible to format a partition to ext4 in U-Boot. It is required to boot to kernel and write rootfs to user partition after formatting it to ext4. Kernel image and DT are expected to be present in the /boot folder of rootfs.

To boot kernel from eMMC, use the following commands after writing rootfs to user partition:

=> setenv mmcdev 0
=> setenv bootpart 0
=> boot

3.1.1.5.6. Booting to U-Boot prompt from USB storage

Booting to U-Boot prompt from USB storage is supported. The following are the steps to be followed,

  1. Build the bootloader images using default “am64x_evm_r5_defconfig” and “am64x_evm_a53_defconfig” configs files. The configs required for USB MSC boot are already enabled. For instructions to build the bootloader images please refer to Build U-Boot.

  2. Create a FAT32 partition with boot flag enabled on the USB storage device.

  3. Copy the bootloader images(tiboot3.bin, tispl.bin, u-boot.img) into the above created partition.

  4. Set the boot mode switches to usb host mode by referring to the Technical Reference manual.

  5. Connect the USB Mass storage device with the bootloader images and boot up the board.

Note

While using usb reset or usb start command in U-Boot, or booting from a USB Mass storage device, some of the USB devices fail to get detected. This issue is seen because these USB devices are failing to follow the spec for power good delay. It can be resolved by overriding the power good delay using the environment variable usb_pgood_delay. Setting it to 2000 should be good enough for all cases.

3.1.1.5.7. Booting Linux from USB storage

To load the Linux kernel, Device Tree and the Root file system from USB Mass storage device, the following changes are required to be done,

  • U-Boot

    1. In U-Boot the USB controller can be used in either host or peripheral mode. For booting to linux kernel from USB storage device, the USB port is to be set as host.

    2. By default, the USB controller is set in peripheral mode.

    3. If the boot media used to boot to U-Boot is USB Host mode(Booting to U-Boot prompt from USB storage) then, the USB controller is set to host mode during runtime. Therefore, no changes would be required in this case.

    4. If a boot media other than USB Host is used, the USB controller needs to be set host mode and custom bootloader images are required to be built. Please refer to note in section Booting tiboot3.bin, tispl.bin and u-boot.img from eMMC boot partition (For K3 class of SoCs)

  • Kernel

    1. In kernel, by default the USB subsystem is built as modules. For booting from USB mass storage device, USB subsytem is required to be built into the image. This can be done by making the following changes in the configuration used for building kernel,

    CONFIG_USB=y
    CONFIG_USB_XHCI_HCD=y
    CONFIG_USB_XHCI_PLATFORM=y
    CONFIG_USB_STORAGE=y
    CONFIG_USB_GADGET=y
    CONFIG_USB_CDNS3=y
    CONFIG_USB_CDNS3_GADGET=y
    CONFIG_USB_CDNS3_HOST=y
    CONFIG_USB_CDNS3_TI=y
    
  • Copying the images to USB storage device

    1. After making the required changes mentioned above, build the kernel, device tree file and modules

    2. The USB Mass storage device should have two partitions,

  • During the boot, cancel the autoboot at U-Boot and run the following command on U-Boot prompt

    => run usbboot
    

3.1.1.5.8. Steps for working around SD card issues

In some cases issue can be seen while using some SD cards, like

  1. Error while trying to initialize,

    U-Boot SPL 2021.01-g74fc69c889 (May 19 2022 - 02:44:29 +0000)
    SYSFW ABI: 3.1 (firmware rev 0x0008 '8.3.2--v08.03.02 (Jolly Jellyfi')
    Trying to boot from MMC2
    spl: mmc init failed with error: -110
    SPL: failed to boot from all boot devices
    ### ERROR ### Please RESET the board ###
    

Given below are the list of various workarounds that can be done in the device tree node to get SD card working. The workarounds are ordered in increasing order of reducing performance.

All the mentioned below, are to be done in the MMCSD device tree node corresponding to the SD instance. This is usually the first(index starting from zero) instance.

  1. Restricting to a given speed mode

    • By default the U-Boot driver tries to enumerate a SD card in the highest supported speed mode. Given below is the order in which the driver tries to enumerate a SD card

      • SDR104

      • SDR50

      • DDR50

      • SD HS

      • SD legacy

    • These speed capabilites can be masked using device tree property sdhci-caps-mask.

      • Limit to SDR50: sdhci-caps-mask = <0x00000004 0x00000000>

      • Limit to DDR50: sdhci-caps-mask = <0x00000006 0x00000000>

      • Limit to SD HS: sdhci-caps-mask = <0x00000007 0x00000000>

      • Limit to SD legacy: sdhci-caps-mask = <0x00000007 0x00200000>

        &sdhci1 {
            /* SD/MMC */
           vmmc-supply = <&vdd_mmc1>;
           vqmmc-supply = <&vdd_sd_dv>;
           pinctrl-names = "default";
           pinctrl-0 = <&main_mmc1_pins_default>;
           ti,driver-strength-ohm = <50>;
           disable-wp;
           sdhci-caps-mask = <0x00000006 0x00000000>; /* Limiting to DDR50 speed mode */
        };
        
  2. Increase power cycle period

    • Increasing the delay while power cycling the SD card. This can be done by increasing the delay value in the diff indicated below,

      diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
      index f486e2a2c364..38cc956b3d53 100644
      --- a/drivers/mmc/mmc.c
      +++ b/drivers/mmc/mmc.c
      @@ -2761,7 +2761,7 @@ static int mmc_power_cycle(struct mmc *mmc)
               * SD spec recommends at least 1ms of delay. Let's wait for 2ms
               * to be on the safer side.
               */
      -       udelay(2000);
      +       udelay(4000);
              return mmc_power_on(mmc);
       }
      
  3. Reduce the bus width

    • The SD interface supports a bus width of 4. It can be reduced to 1 by changing the bus-width device tree property from 4 to 1.

      diff --git a/arch/arm/dts/k3-am62-main.dtsi b/arch/arm/dts/k3-am62-main.dtsi
      index c06ec7355035..4ab29b6aa4b7 100644
      --- a/arch/arm/dts/k3-am62-main.dtsi
      +++ b/arch/arm/dts/k3-am62-main.dtsi
      @@ -373,7 +373,7 @@
                      ti,itap-del-sel-sdr12 = <0x0>;
                      ti,itap-del-sel-sdr25 = <0x0>;
                      ti,clkbuf-sel = <0x7>;
      -               bus-width = <4>;
      +               bus-width = <1>;
       };
      
       sdhci2: mmc@fa20000 {