The content of this page refers to RZ/G2L, however, given the similarities with RZ/V2L, RZ/G2LC and RZ/G2UL, the information included can be considered valid for these devices too.

RZ/G2L boot modes and typical boot storage media

RZ/G2L boot modes are summarized in the table below.

Selection of RZ/G2L boot modes

MD_BOOT2 to MD_BOOT0Boot ModeInterface ModuleConnected Device
000Boot mode 0SDHI0eSD (3.3 V at startup)
001Boot mode 1SDHI01.8-V eMMC
010Boot mode 2SDHI03.3-V eMMC
011Boot mode 3SPIBSC1.8-V Single Quad or Octal serial flash memory
100Boot mode 4SPIBSC3.3-V Single or Quad serial flash memory
101Boot mode 5SCIF0Downloading through SCIF

When the eMMC is delivered from the manufactures is normally divided into several areas as shown below.

In most of the Linux applications covered by the RZ/G2L, when it comes to non-volatile memory there are two main use cases:

  • QSPI and eMMC. QSPI is normally used for firmware / boot loaders (i.e. ATF and u-boot) whereas eMMC for kernel and rootfs.

  • eMMC only. In this case one of the two eMMC boot partitions is used for boot loaders and the user partition is then used for rootfs and kernel.

Very often there is only one ext partition in the user space and Linux kernel and device tree are stored in it (e.g. /boot folder).

There might be other special cases but we can confidently state that these cover the great majority. We can also reasonably say that being the RZ/G2L a low-end device, there is the tendency to remove the QSPI to save money on the BOM.

At the end of the production line of course non-volatile memories are virgin (with a notable exception explained later) and need to be programmed. Usually firmware and bootloaders are relatively small (less than 1MB in total), kernel is instead in the tens of megabyte range and rootfs can go up to several hundreds of megabytes. To transfer this amount of data a fast interface is indeed required.

Flash Programming options

RZ/G2L cannot boot from USB, so at the end-of-line there are a few real viable options:

  1. Boot from SCIF (UART)
  2. Use JTAG
  3. It is worth to mention that, in general, if a QSPI FLASH is present on the custom board, it can also be bought preprogrammed
  4. Use a temporary QSPI flash card
  5. Boot from SD

In any of the cases above the goal is to have U-Boot up and running, then there are plenty of options to program the rootfs: ethernet, SD card, USB as host, USB with Mass Storage gadget, fastboot or even boot Linux kernel + initramfs.

With option 1, you can download Flash Writer and program the bootloaders, Arm Trusted Firmware (ATF) and U-Boot, into QSPI / eMMC boot partition, then reset and run U-Boot.

With option 2, you can download ATF and U-Boot via JTAG and then run the boot loaders without having to initially program them. Once U-Boot runs, you can program both bootloaders and rootfs.

With option 3, QSPI has already bootloaders pre-programmed, so U-Boot is already available.

With option 4, a QSPI flash card is somehow attached to the board that needs to be programmed. The QSPI flash contains ATF and U-Boot and potentially also the root file system to be programmed, depending on the size of both. More details are available here.

With option 5, a you boot from a uSD card that contains ATF, U-Boot and root file system to be programmed into QSPI / eMMC. It may be a bit tricky because the device can only boot from SDIO0, that has shared with eMMC if eMMC is then the device where you want to boot from.

Unattended Flash Programming booting from SCIF (USB host)

All the options above may not require any human intervention and can be to a certain extent automatized.

In the rest of this page follow some examples on how to implement a fully atomized flash programming. More in particular we will focus on option 1, where:

  1. ATF and U-Boot are programmed using the SCIF.
  2. At the reboot U-Boot loads and boots kernel and the initramfs from USB.
  3. Then a custom init script is used of program the root file system stored on the USB thumb to the eMMC.
  4. After eMMC programming U-Boot is replaced, mainly to have a new set of environment variables to boot the final kernel / rootfs.

It is assumed that all binaries to be programmed are already available, for example as result of the porting of the BSP. This is the list of items that are needed:

  • ATF binaries (e.g. bl2_bp.bin, bl31.bin);
  • u-boot source code to generate temporary and definitive binaries (u-boot.bin);
  • Kernel image and device tree (e.g. Image, r9a07g044l2-smarc-smarc-rzg2l.dtb);
  • A system image file including including root file system (e.g sd_card.img.gz) that can be easily created using this script.

However, there are other things to be done beforehand: step 0.

Step 0 - Environment set-up

Temporary u-boot

u-boot used at the first step is not the definitive one, its default environment parameters are adapted to allow the next steps to be executed automatically. The default environment parameters are configured in include/configs/BOARD_NAME.h, for example for the RZ/G2L smarc board:

#define CONFIG_EXTRA_ENV_SETTINGS \
	"bootm_size=0x10000000 \0" \
	"baudrate=115200 \0" \
	"bootargs=rw rootwait earlycon root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh \0" \
	"bootdelay=3 \0" \
	"bootimagerd=booti 0x4A080000 0x50000000 0x48000000 \0" \
	"produsbbootargs=setenv bootargs rw rootwait earlycon root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh \0" \
	"usbload=usb start;fatload usb 0 0x4A080000 Image;fatload usb 0 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;fatload usb 0 0x50000000 core-image-minimal-smarc-rzg2l-mod.cpio.gz.u-boot;run produsbbootargs \0"

#define CONFIG_BOOTCOMMAND	"run usbload;run bootimagerd"

These parameters ensure that:

  1. After a boot delay of 3 seconds the command usbload is executed;
  2. usbload, as the name suggests, after having initialized USB, loads kernel, device tree and initramfs into DDR.
  3. boots kernel with initramfs and a custom init script that is in charge of programming kernel, device tree and the definitive root fs into eMMC.

It is important to note that u-boot has to be built with USB support, obviously. It may not be enabled by default but it is there starting from VLP3.0.3.

u-boot binary (u-boot.bin) has to be combined with bl3x to generate fip.bin, assuming bl31.bin only:

tools/fiptool/fiptool create --align 16 --soc-fw build/g2l/release/bl31.bin --nt-fw u-boot.bin fip.bin

fiptool is a tool distributed with ATF.

Generating u-boot variables binary

Instead of building another ad-hoc version of u-boot, we can create a environment variable binary file that can be programmed to a specific location using Flash Writer. These environment parameters are the same as the previous section. To do that we can use a utility called mkenvimage. First of all we have to create a text file (u-boot-env.txt) with the environment variables as we would read them from u-boot, e.g.:

bootm_size=0x10000000
baudrate=115200
bootargs=rw rootwait earlycon root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh
bootcmd=run usbload;run bootimagerd
bootdelay=3
bootimagerd=booti 0x4A080000 0x50000000 0x48000000
produsbbootargs=setenv bootargs rw rootwait earlycon root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh
usbload=usb start;fatload usb 0 0x4A080000 Image;fatload usb 0 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;fatload usb 0 0x50000000 core-image-minimal-smarc-rzg2l-mod.cpio.gz.u-boot;run produsbbootargs

Then we can convert this into a binary using mkenvimage:

mkenvimage u-boot-env.txt -s 0x20000 -o u-boot-env.bin

What is important to notice is the size (-s). This parameter must match what is configured in u-boot, take note also of the offset and partition where the environment variables are stored. If the command gets executed correctly, we will end up with a binary file (u-boot-env.bin) whose size is exactly what specified, in the example above exactly 128KB.

Once the kernel is running, instead of dealing with binaries that are somewhat not very convenient, we can use the utilities that are part of the former u-boot-fw-utils package, nowadays called libubootenv: fw_printenv and fw_setenv.

In order to get it build and be part of the generated image, the following packages shall be added in the local.conf (Yocto):

IMAGE_INSTALL_append = " \
   libubootenv \
   libubootenv-bin \
"

⚠️ Note, if Yocto complains about multiple u-boot versions, then also add this line into local.conf:

RRECOMMENDS_libubootenv-bin_remove_class-target = " u-boot-default-env"

To use these two utilities a text configuration file (/etc/fw_env.config), including a single text line to tell the tools where to find the data:

/dev/mmcblk0boot1               -0x20000        0x20000

The meaning is quite obvious. In the first column we find the device where the data is stored (in this example it is eMMC, boot partition 2). The second column is the offset, in a similar way it is defined in the u-boot parameter, so a negative number is treated as a backward offset from the end of of the eMMC device/partition. The last column is the size.

One last step is to create a script file that is going to be used by fw_setenv to (re)set the environment variables to what they will have to look like eventually. The syntax is very simple:

key [space] value

Here the complete script final_env_variables.txt content.

⚠️ Note that if the redundant environment support is enabled in u-boot (CONFIG_SYS_REDUNDAND_ENVIRONMENT=y), then the configuration file must include two lines, where the second points to the redundant part, for example if CONFIG_ENV_OFFSET_REDUND=0xFFFC0000 CONFIG_ENV_OFFSET=0xFFFE0000 CONFIG_ENV_SIZE=0x20000:

/dev/mmcblk0boot1               -0x20000        0x20000
/dev/mmcblk0boot1               -0x40000        0x20000

Initrd script

This is the script that is going to be executed right after the kernel has finished booting.

Initramfs creation

Any root file system, including the final one that was created for the final application can be turned into a initramfs. However you have to take in account that it is convenient to have a small one. First it is loaded quicker from the thumb drive, then it has to be small enough to comfortably fit into the DRAM. In this example the initial rootfs is created using Yocto: bitbake core-image-minimal. You may want to add packages like mtd-utils and mmc-utils that are useful to program QSPI and eMMC and libubootenv to deal with environment variables.

Once the minimal rootfs has been created, we have to modify it to add the custom initrd script (see previous section). In general, assuming you have your rootfs in the usual tar.gz/bz2 format, first of all we have to untar/unzip it into a temp folder:

mkdir temp
sudo tar -xvf core-image-minimal-smarc-rzg2l.tar.bz2 -C temp

You want to use sudo because then all the files have root owner.

cd temp

Assuming in the same folder the initrd script, as well as bl2, fip (definitive version) and other files are available:

sudo cp ../my_init_flash_prog.sh home/root/
sudo cp ../bl2_bp.bin home/root/ 
sudo cp ../fip.bin home/root
sudo cp ../final_env_variables.txt home/root
sudo cp ../fw_env.config etc/

Let's get the initrd script executable:

sudo chmod +x home/root/my_init_flash_prog.sh

We have to create a init symbolic link into the root folder:

sudo ln -s sbin/init init

Now we are ready to pack the modified files to cpio ‘newc’ format:

sudo find . | sudo cpio --create --format='newc' > ../core-image-minimal-smarc-rzg2l-mod.cpio

Gzip it:

cd ..
gzip -v core-image-minimal-smarc-rzg2l-mod.cpio

Finally create a u-boot image:

mkimage -n "core-image-minimal-smarc-rzg2l-mod" -A arm64 -O linux -T ramdisk -C none -d core-image-minimal-smarc-rzg2l-mod.cpio.gz core-image-minimal-smarc-rzg2l-mod.cpio.gz.u-boot

If the last command fails, then you need to install u-boot tools. For example in Ubuntu:

sudo apt install u-boot-tools

USB thumb drive preparation

We can now prepare a thumb drive with the following content:

  • Kernel and device tree (Image, r9a07g044l2-smarc-smarc-rzg2l.dtb);
  • Root file system image (sd_card.img.gz);
  • Initram fs (core-image-minimal-smarc-rzg2l-mod.cpio.gz.u-boot)

Step 1 - Programming ATF and u-boot via SCIF

The main tool that can assist in performing external non-volatile memory (QSPI and eMMC) is Flash Writer. Depending on the host PC used, you can either use a bash script or a TeraTerm macro. In both cases you would need two / three files:

  • bl2.bin
  • fip.bin
  • u-boot-env.bin (optional)

The file names may vary a bit. These are either the output of Yocto or generated by combining ATF and U-Boot binaries. Actually the first one is generated by ATF directly whereas the second is the generated by the Firmware Image Package (FIP) utility by combining BL3x binaries (BL31 secure monitor, optionally BL32 OP-TEE and BL33 u-boot).

u-boot-env.bin can be created as per instructions here.

Linux script

A Linux bash script is available here. Please refer to the README for help on the usage.

⚠️ Note that this script cannot automatically write/update u-boot environment variables.

Windows TeraTerm macro

Usually dealing with this type of devices a Linux host PC is normally available. However sometimes it might be convenient to have a quick way to program the bootloaders using Windows. Especially during production, a Windows PC may be more convenient than a Linux PC.

Instead of using an ad-hoc tool developed only for the RZ/G2L the idea is to use a generic terminal utility. Tera Term is an open source tool that has some nice scripting capabilities embedded: a Tera Term script is called MACRO. The developed macro "replaces" the user and provides inputs to Flash Writer, whose binary is also downloaded automatically. There are just a couple of parameters that you would need to change (open the macro with a standard txt editor), stuff like COM port or the name of the Flash Writer binary to be used and whether the target is QSPI or eMMC. The "UNATTENDED" parameter suppresses all the user interaction apart from errors.

In general environment parameters can be saved in different non-volatile media, the most common are eMMC and QSPI. The TeraTerm macro can program the environment variable binary file in the eMMC only. Env variables can be programmed in different areas though: user, boot partition 1 or boot partition 2. Default RZ/G2L u-boot stores them in boot partition 2 (boot partition 1 is used for ATF and FIP). By default the u-boot parameter:

CONFIG_ENV_OFFSET=0xFFFE0000

stores the environment variables at a backwards offset from the end of the eMMC boot partition 2. eMMC may have different boot partition sizes, the actual value can be obtained by reading the extended CSD register 226, for example, using Flash Writer command EM_DECSD we will get something like:

[EXT_CSD Field Data]
[...]
[228:228]  BOOT_INFO                                  0x07
[226:226]  BOOT_SIZE_MULTI                            0xFC
[225:225]  ACC_SIZE                                   0x00
[...]

The actual size can be obtained by multiplying 0xFC by 128Kbytes, so 252x128x1.024=33.030.144 bytes=32.256KB=31.5MB.

On the other hand 0xFFFE0000 shall be read as -0x20000 or -128KB. So taking in account that in Flash Writer we have to configure a sector (eMMC default size = 512), in our case we have to choose in the TeraTerm macro:

33.030.144 - 131.072 (128K) = 32.899.072 that should be divided by 512 = 64.256 = 0xFB00.

It is assumed that MD_BOOTx pins are already configured for the final boot mode. However, if the target flash is virgin / erased, the boot mode selected fails over to SCIF download, allowing the Flash Writer bin to be downloaded.

When the procedure is complete, the system gets reset and the system boots using the newly programmed files.

SCIF download mode acceleration (RZ/G2L-LC only)

It is possible to download a very small executable that just reconfigures the SCIF0 baudrate from 115200 to 921600, such that the following binary (normally Flash Writer) is downloaded much faster. It may not be convenient when doing things manually, but when using a script (Teraterm or others) it allows to reduce the overall bootloaders programming time significantly.

Step 2

At this step there's not anything to do, just to check that what we've done at step 0 works consistently. If everything is ok the system goes thru the standard boot stages and u-boot load kernel and initrd from the USB thumb drive.

Step 3

At this stage the custom initrd script is executed, programming the rootfs onto the eMMC user area. Note that at the end of the copy the ext4 partition is resized to the max allowed by the eMMC. Again, we just need to check that everything is inline with expectations.

Step 4

The last step is needed to replace u-boot default environment variables to values that allow the final rootfs to be booted from eMMC. This is the version of u-boot that was created originally, anyway here below the environment variables you may want to use:

#define CONFIG_EXTRA_ENV_SETTINGS \
	"bootm_size=0x10000000 \0" \
	"prodsdbootargs=setenv bootargs rw rootwait earlycon root=/dev/mmcblk1p2 \0" \
	"prodemmcbootargs=setenv bootargs rw rootwait earlycon root=/dev/mmcblk0p2 \0" \
	"bootimage=booti 0x4A080000 - 0x48000000 \0" \
	"emmcload=fatload mmc 0:1 0x4A080000 Image;fatload mmc 0:1 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;run prodemmcbootargs \0" \
	"sd1load=fatload mmc 1:1 0x4A080000 Image;fatload mmc 1:1 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;run prodsdbootargs \0" \
	"bootcmd_check=if mmc dev 1; then run sd1load; else run emmcload; fi \0"

#define CONFIG_BOOTCOMMAND	"env default -a;run bootcmd_check;run bootimage"

Or in terms of fw_setenv script:

baudrate=115200
bootargs=rw rootwait earlycon root=/dev/mmcblk0p1
bootargsrd=rw rootwait earlycon root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh
bootcmd=run bootcmd_check;run bootimage
bootcmd_check=if mmc dev 1; then run sd1load; else run emmcload; fi
bootdelay=2
bootimage=booti 0x4A080000 - 0x48000000
bootm_size=0x10000000
emmcload=fatload mmc 0:1 0x4A080000 Image;fatload mmc 0:1 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;run prodemmcbootargs
loadaddr=0x58000000
prodemmcbootargs=setenv bootargs rw rootwait earlycon root=/dev/mmcblk0p2
prodsdbootargs=setenv bootargs rw rootwait earlycon root=/dev/mmcblk1p2
sd1load=fatload mmc 1:1 0x4A080000 Image;fatload mmc 1:1 0x48000000 r9a07g044l2-smarc-smarc-rzg2l.dtb;run prodsdbootargs

Unattended Flash Programming booting from SCIF (USB device)

In the previous section the device acts as a USB host and the files are stored on the external USB thumb drive.

In this section the idea is to have the device acting as USB device and a PC can be used to download and/or flash the eMMC. It goes without saying that the first step is to to make sure that u-boot is running (so it is programmed using SCIF as described in the previous section), then when u-boot is running we can use:

  • fastboot over USB
  • USB Mass Storage gadget (UMS)

Step 0 - Environment set-up

Similarly to what described in the previous section you may need to prepare something in advance. First of all u-boot has to be patched to have USB device and fastboot / ums working. VLP3.0.3 and corresponding u-boot version do not support it. It may be not needed in the future but for now you need to use this patch. If you are building u-boot outside of Yocto then you need to clone and checkout a specific commit:

git clone https://github.com/renesas-rz/renesas-u-boot-cip
git checkout 8f3828c87d179b375b1473fcaac84d610d9259dd

Then apply the patch:

patch -p1 < /PATH_TO_PATCH/fastboot-ums-usb-dev-emmc.patch

Then build as usual. The u-boot binary must be combined with bl31 into the FIP.

If you are using Yocto (not normally recommended), after a complete build:

MACHINE=smarc-rzg2l bitbake firmware-pack trusted-firmware-a optee-os flash-writer u-boot -c cleanall
MACHINE=smarc-rzg2l bitbake u-boot -c devshell

Then when the prompt appears:

patch -p1 < /PATH_TO_PATCH/fastboot-ums-usb-dev-emmc.patch
exit

Then:

MACHINE=smarc-rzg2l bitbake firmware-pack

This command regenerates the files that need to be programmed (bl2 and FIP).

You need a system image (including the partitioning, i.e. ext4, fat if any, etc), for example generated using the image creator script mentioned before.

⚠️ Note: it is important that the image size is a multiple of 4096. This can be achieved using "G" in the script option:

TOTAL_IMAGE_SIZE=2G    # MBR/partition table + FAT partition + ext partition

You may also want to generate a custom u-boot or a specific u-boot environment variables binary as per previous section, for example to make sure that the fastboot / ums command is automatically executed when the system boots up for the first time.

Alternatively you can create the images for each partition and then program them one by one (just google to get more information on how to do that).

You also need to create the images that will then be programmed into eMMC boot partition 1 and 2. This can be done easily using dd, for example:

dd if=/dev/zero of=boot1.test bs=512 count=64512
dd if=/PATH_TO_BL2/bl2_bp-smarc-rzg2l_pmic.bin of=boot1.bin seek=1 conv=notrunc
dd if=/PATH_TO_FIP/smarc-rzg2l/fip-smarc-rzg2l.bin of=boot1.test seek=128 conv=notrunc

The previous commands assume that the boot partition is 64512 512-byte blocks in size. You may want to check it for your specific eMMC.

Similarly for boot partition 2:

dd if=/dev/zero of=boot1.test bs=512 count=64512
dd if=/PATH_TO_ENV_VAR/bl2_bp-smarc-rzg2l_pmic.bin of=boot1.bin seek=64256 conv=notrunc

The last command assumes (default in VLP u-boot) that the environment variables are 256 512-byte blocks big, placed at the end of the boot partition 2.

Step 1 - Programming ATF and u-boot via SCIF

This part is exactly the same as described before. Arm Trusted Firmware and u-boot have to be flashed into the selected bootable memory beforehand.

Step 2 - Using fastboot

This section can be automated, both on the PC side and the target device side (using specific u-boot environment variables) but the flow is described here for the sake of clarity.

fastboot is available for different platforms and operating systems. In Ubuntu it can be installed very easily:

sudo apt install fastboot

On Windows you may need to install a driver and the fastboot utility, you can just google, there are plenty of guides online.

In the u-boot configuration make sure that the following configs are enabled (and potentially rebuilt it):

CONFIG_USB_FUNCTION_FASTBOOT=y
CONFIG_FASTBOOT_BUF_ADDR=0x4D000000
CONFIG_FASTBOOT_BUF_SIZE=0x8000000
CONFIG_FASTBOOT_USB_DEV=28
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
CONFIG_FASTBOOT_MMC_USER_SUPPORT=y

Note that with fastboot we can only program the eMMC (no QSPI). There are different ways to do this, in the rest of this section some examples are given.

When the device reboots the u-boot prompt appears, what we want to define (again it can be already part of the environment variables) is the serial number that is used to identify the specific board connected to the PC:

setenv serial# 'Renesas1'
saveenv

Note that many target boards can be connected via USB at the same time and fastboot may address one by one separately assuming that they have different serial numbers.

Now we can start fastboot on the device:

fastboot usb 27

Normally no message is shown, but no commands can be input any longer.

Then on the PC side we can verify the connected devices:

fastboot devices

This should list the connected board(s):

fastboot devices
Renesas1     fastboot

Another useful command is:

fastboot reboot

That resets the target board.

Booting a temporary Linux using fastboot

fastboot can be used to boot a temporary Linux that can be used to program the eMMC, in a similar way as was shown before. In order to do we need to prepare a boot image. This image can be created using the mkbootimg utility. For ubuntu:

sudo apt install mkbootimg

The boot image shall contain kernel, device tree and the initial RAM disk:

mkbootimg --kernel /PATH_TO_KERNEL_IMAGE/Image --kernel_offset 0x2080000 --pagesize 2048 --base 0x48000000 --dtb /PATH_TO_DTB/r9a07g044l2-smarc-smarc-rzg2l.dtb --cmdline "rw rootwait root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh" --ramdisk /PATH_TO_INITRD/smarc-rzg2l/core-image-minimal-smarc-rzg2l-mod.cpio --ramdisk_offset 0x8000000 --header_version 2 --output boot.img

Let's analyze the command options:

--kernel /PATH_TO_KERNEL_IMAGE/Image --kernel_offset 0x2080000

This part configures the kernel image and the offset starting from the base (see below) where the kernel has to be loaded and executed. You may need to adjust but normally apart from the path you can keep use the rest as is.

--pagesize 2048 --base 0x48000000

This configures the page size and the base address for the offsets that are used for the items that are loaded. 0x48000000 is the base address of the DDR, it can be configured but only if you know what you are doing.

--dtb /PATH_TO_DTB/r9a07g044l2-smarc-smarc-rzg2l.dtb 

Device tree with its path, that may be the same as the kernel.

--cmdline "rw rootwait root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh"

These are the kernel bootargs, as you may have already guessed. In this example the initial ram disk is used and also a custom initrd script that may contain the procedure to perform the flash programming itself.

--ramdisk /PATH_TO_INITRD/smarc-rzg2l/core-image-minimal-smarc-rzg2l-mod.cpio --ramdisk_offset 0x8000000

This line configures the ramdisk that can be created as per previous instructions. It is important to note that you must use the non gzipped version.

--header_version 2 --output boot.img

Here of course you can change the output file name but you do not want to change the header version. Version 2 is the one that support the inclusion of a device tree.

Before we can use this image, some environment variables must be defined otherwise the boot fails, so once stopped at u-boot:

setenv initrd_high ffffffffffffffff
setenv fdt_high ffffffffffffffff
setenv fdtaddr ffffffffffffffff

The first two disable the initial ram disk and flattened device tree copy (it is not needed, fastboot downloads stuff into DDR already). You can find more details here. The last one is necessary to have a value defined since u-boot searches and tries to replace the value with the one that is calculated at runtime. If not there, a panic related to a synchronous abort occurs.

On the device:

fastboot usb 27

On the PC:

fastboot boot boot.img

That would result in something like (PC):

micbis@micbis-ThinkPad-T490:~/renesas/temp$ fastboot boot boot.img 
Sending 'boot.img' (123840 KB)                     OKAY [ 10.038s]
Booting                                            FAILED (Status read failed (No such device))
fastboot: error: Command failed

You can safely ignore the error message.

On the device:

Starting download of 126812160 bytes
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
.....
downloading of 126812160 bytes finished
Booting kernel at 0x000000004d000000...


## Booting Android Image at 0x4d000000 ...
Kernel load addr 0x4a080000 size 17079 KiB
Kernel command line: rw rootwait root=/dev/ram0 rdinit=/home/root/my_init_flash_prog.sh
RAM disk load addr 0x50000000 size 106717 KiB
   Loading Kernel Image
   Using Device Tree in place at 00000000548e6000, end 00000000548f2b51

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0000000000 [0x412fd050]
[    0.000000] Linux version 5.10.158-cip22-yocto-standard (oe-user@oe-host) (aarch64-poky-linux-gcc (GCC) 8.3.0, GNU ld (GNU Binutils) 2.31.1) #1 SMP PREEMPT Sat Feb 27 02:21:18 UTC 2021
[    0.000000] Machine model: Renesas SMARC EVK based on r9a07g044l2
[    0.000000] earlycon: scif0 at MMIO 0x000000001004b800 (options '115200n8')
[    0.000000] printk: bootconsole [scif0] enabled
[    0.000000] efi: UEFI not found.
[    0.000000] [Firmware Bug]: Kernel image misaligned at boot, please fix your bootloader!
[    0.000000] Reserved memory: created CMA memory pool at 0x0000000058000000, size 256 MiB
[    0.000000] OF: reserved mem: initialized node linux,cma@58000000, compatible id shared-dma-pool
[    0.000000] Reserved memory: created CMA memory pool at 0x0000000068000000, size 128 MiB

[... cut ....]

⚠️ Note: the boot.img size cannot be bigger than 128MB, the default configured fastboot buffer size. It may be overcome by modifying the buffer size / location but it has some impact on other parameters as well. A configuration worth to try (if you know what you are doing) is: fastboot buffer address 0x70000000, fastboot buffer size 0x10000000 (256MB), mkibootimage base address 0x48000000, kernel offset 0x2080000, ramdisk offset 0x18000000.

Flashing eMMC hw user partition

Then, on the PC:

fastboot -s Renesas1 flash mmc0 /PATH_TO_IMAGE/sd_card.img

This would result in something like:

Invalid sparse file format at header magic
Sending sparse 'mmc0' 1/4 (131037 KB)              OKAY [ 10.839s]
Writing 'mmc0'                                     OKAY [ 30.834s]
Sending sparse 'mmc0' 2/4 (130859 KB)              OKAY [ 10.802s]
Writing 'mmc0'                                     OKAY [113.153s]
Sending sparse 'mmc0' 3/4 (130710 KB)              OKAY [ 10.882s]
Writing 'mmc0'                                     OKAY [  6.845s]
Sending sparse 'mmc0' 4/4 (78001 KB)               OKAY [  6.382s]
Writing 'mmc0'                                     OKAY [ 49.315s]
Finished. Total time: 240.980s

And on the device:

** Bad device specification mmc mmc0_a **
Couldn't find partition mmc mmc0_a
** Bad device specification mmc mmc0 **
Couldn't find partition mmc mmc0
Starting download of 134182660 bytes
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
.............................................................
downloading of 134182660 bytes finished
Flashing sparse image at offset 0
Flashing Sparse Image
........ wrote 658927616 bytes to 'mmc0'
Starting download of 134000524 bytes
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
............................................................
downloading of 134000524 bytes finished
Flashing sparse image at offset 0
Flashing Sparse Image
........ wrote 2432077824 bytes to 'mmc0'
Starting download of 133847984 bytes
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
...........................................................
downloading of 133847984 bytes finished
Flashing sparse image at offset 0
Flashing Sparse Image
........ wrote 144703488 bytes to 'mmc0'
Starting download of 79873292 bytes
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
..........................................................................
.................
downloading of 79873292 bytes finished
Flashing sparse image at offset 0
Flashing Sparse Image
........ wrote 1059258368 bytes to 'mmc0'

You can safely ignore the error messages.

There's also the possibility to program partition images one by one. To do this you also have to program the Master Boot Record (MBR) separately:

fastboot flash mbr part.mbr
fastboot flash 0:1 fat-partition.img
fastboot flash 0:2 core-image-weston-smarc-rzg2l.ext4

In this example the eMMC is again partitioned in two, one FAT and one ext4. The important point to highlight is that 0:n means device 0 partition n.

Flashing eMMC boot area

Boot partitions can be programmed as well:

$ fastboot -s Renesas1 flash mmc0boot0 ./boot1.bin 
Sending 'mmc0boot0' (32256 KB)                     OKAY [  2.650s]
Writing 'mmc0boot0'                                OKAY [  1.844s]
Finished. Total time: 4.552s
$ fastboot -s Renesas1 flash mmc0boot1 ./boot2.bin 
Sending 'mmc0boot1' (32256 KB)                     OKAY [  2.638s]
Writing 'mmc0boot1'                                OKAY [  1.828s]
Finished. Total time: 4.805s

That results:

** Bad device specification mmc mmc0boot0_a **
Couldn't find partition mmc mmc0boot0_a
** Bad device specification mmc mmc0boot0 **
Couldn't find partition mmc mmc0boot0
Starting download of 33030144 bytes
..........................................................................
..........................................................................
..........................................................................
..............................
downloading of 33030144 bytes finished
........ wrote 33030144 bytes to EMMC_BOOT1

** Bad device specification mmc mmc0boot1_a **
Couldn't find partition mmc mmc0boot1_a
** Bad device specification mmc mmc0boot1 **
Couldn't find partition mmc mmc0boot1
Starting download of 33030144 bytes
..........................................................................
..........................................................................
..........................................................................
..............................
downloading of 33030144 bytes finished
........ wrote 33030144 bytes to EMMC_BOOT2

⚠️ Note that if the eMMC is virgin you also need to program the non-volatile registers.

Step 2 - Using USB Mass Storage (ums)

Another option (alternative to fastboot) is to use the USB Mass Storage gadget and the ums command:

ums usb0

Then the target board / device shows up as a mass storage device and any Linux tool like dd or Windows tool like Balena etcher can be used to program the eMMC HW user partition. Obviously the "disk" can also be partitioned using fdisk or gparted and then the partitions can be programmed individually.

It is possible to select the eMMC HW partitions:

ums usb0 mmc0.1

This command selects mmc device 0 HW partition 1, that is normally boot area 1. Similarly for boot area 2.

It is also possible to select eMMC "standard" partitions:

ums usb0 mmc 0:2

This command selects mmc device 0 (assuming user HW partition) partition 2, that is the ext4 in the standard partitioning scheme of the image creator script.

⚠️ Note: you may want to make sure that the following configs are enabled in u-boot (and potentially rebuild it):

CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="Renesas"
CONFIG_USB_GADGET_VENDOR_NUM=0x18D1
CONFIG_USB_GADGET_PRODUCT_NUM=0x4E23
CONFIG_USB_RENESAS_USBHS=y
CONFIG_CMD_USB=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MASS_STORAGE=y
CONFIG_CMD_USB_MASS_STORAGE=y

Use JTAG

In general there are two possibilities here:

1) Download a flasher (maybe a modified version of FlashWriter) and the bl2/fip binaries to be programmed via JTAG, then launch the programming. At the following boot u-boot is running, so whatever already explained in the rest of this wiki page can be used.

2) Download temporary TF-A and u-boot via JTAG and do whatever already explained in the rest of this page.

Note that it may not be convenient (even if theoretically possible) to program the rootfs using the JTAG interface. JTAG is definitely faster than UART but it may be slower than other fast interfaces like USB or ethernet.

Download a flasher

TBD

Download temporary TF-A / u-boot

TBD

Unattended Flash Programming booting from SD card

Another viable option is to boot from a uSD card. In this section two approaches are described:

  • Boot from uSD, u-boot loads kernel / initramfs and kernel programs images stored onto an USB thumb drive;
  • Boot from uSD and u-boot programs directly the files (ATF, u-boot and rootfs) stored onto the uSD card itself;

The first option is very similar to what was described in Unattended Flash Programming booting from SCIF sections, the only difference is that the procedure is started from step 2.

The second option allows to program the eMMC/QSPI in one step switching between uSD card to eMMC and viceversa. This switch is only possible in u-boot thanks to some circuitry available on the smarc EVK, that it can be potentially reused / adapted for custom designs.

Boot from uSD (programming using linux)

For this procedure a uSD card is needed as well as an USB thumb drive.

The uSD card contains:

  • ATF, u-boot, programmed into specific sectors to allow the uSD card itself to be bootable;
  • Linux kernel, device tree and initramfs onto a FAT partition;

The USB thumb drive contains the system image to be programmed, again as described here. Actually this split is not mandatory, the kernel, device tree and initramfs could also be stored in the USB thumb drive. Two different storage units are required because the MPU can only boot from sdhi0, so both the uSD card and eMMC must connected on the same interface. However in Linux kernel the switch between uSD and eMMC is not possible at runtime, therefore this switch is done at u-boot only once from uSD to eMMC.

Boot from uSD (programming using u-boot)

In this case a big enough uSD card only is required. Again this micro SD card is bootable (u-boot needs to be patched) and it should be partitioned to store the files to be programmed, i.e. the binaries potentially generated by Yocto (bl2, fip, kernel + dtb and rootfs). In this case it is not required to boot linux for the actual programming but everything is handled at u-boot stage.

Binaries preparation

As mentioned the tricky part here is related to the fact that eMMC and uSD card (to be bootable) share the same interface (SDHI0), therefore the data should be read from uSD to DDR and then written to eMMC. However the rootfs (or entire image with multiple partitions) is usually bigger than the amount of DDR available, therefore this procedure has to be done in chunks. Let us assume that a complete image has been created using this script and that the name of the generated image is SD_image.img, this file can be be split in 512MB chunks using this command:

split -b512M SD_image.img SD_image.img

The output consists of several files, 512MB each named SD_image.imgaa, SD_image.imgab, SD_image.imgac and so on.

To speed things up during read, we can also zip them:

gzip SD_image.imga*

Resulting in as many .gz files. Then it is enough to copy these files onto the FAT partition created on the uSD card.

These steps can also be added to the aforementioned script to have all the files generated in one go.

u-boot preparation

In order to perform the switch from uSD to eMMC, a specific circuitry should be available on the board and this is the case on the RZ/G2L SMARC EVKs.

SD0_DEV_SEL can be driven by a GPIO, P41_1. In reality the circuitry is a bit more complicated because it also takes in account the boot mode and the SDIO bus voltage selection:

It looks a bit complex but from the SW point it is as easy as toggling a GPIO, again P41_1. To do that u-boot source code has to be modified, this is the patch for u-boot 2021.10 needed to allow P41_1 to be toggled in u-boot.

Burn it!

Once booted the board with the modified u-boot, we are ready to program. As mentioned everything relies on the switch between uSD and eMMC, so first thing to do is to create a couple of environment variables to do this:

select_emmc=mw.b 0x11030039 0x00; mmc rescan
select_sdhi0=mw.b 0x11030039 0x02; mmc rescan

0x11030039 is the address of the PORT register 39, bit 1 is what we need to toggle.

BL2

To program bl2, we can create and use this environment variable:

prog_bl2=run select_sdhi0;fatload mmc 0:1 0x48000000 bl2_bp-smarc-rzg2l_pmic.bin;setexpr blocknum $filesize / 200;setexpr blocknum $blocknum + 1;run select_emmc;mmc dev 0 1;mmc write 0x48000000 1 $blocknum;

This needs a bit of explanation. Firstly, since we do not know which interface is currently selected, it's better to make sure we are using sd:

run select_sdhi0

Then, we load the binary into DDR from the fat partition:

fatload mmc 0:1 0x48000000 bl2_bp-smarc-rzg2l_pmic.bin

You may know that when a file is loaded in u-boot, a predefined environment variable is updated ($filesize). This is not enough because we need to know how many 512-byte sectors we have to program and this is what this command does:

setexpr blocknum $filesize / 200

Since most likely the file is not a integer multiple of 512, we need to increment by 1 the result:

setexpr blocknum $blocknum + 1

Then we switch to emmc:

run select_emmc

We select the first boot partition:

mmc dev 0 1

And finally write:

mmc write 0x48000000 1 $blocknum

Note that "1" is the first sector where the BL2 must be programmed.

FIP

Similarly for FIP:

prog_fip=run select_sdhi0; mmc rescan;fatload mmc 0:1 0x48000000 fip-smarc-rzg2l_pmic.bin;setexpr blocknum $filesize / 200;setexpr blocknum $blocknum + 1;run select_emmc;mmc dev 0 1;mmc write 0x48000000 100 $blocknum;

The only notable difference is in the last command, "100" is the sector where FIP is supposed to be programmed.

Environment variables

Most likely we want also to program the final environment variables, using a binary:

prog_envvar=run select_sdhi0; mmc rescan;fatload mmc 0:1 0x48000000 final_env_variables.bin;setexpr blocknum $filesize / 200;run select_emmc;mmc dev 0 2;mmc write 0x48000000 FB00 $blocknum;

Apart from what already described, it is worth to note this command:

mmc dev 0 2

This depends on where the variables are stored, in this example it is assumed the default eMMC 2nd boot partition.

FB00 is the location in terms of sectors where the variables are stored by default.

System image

In this example we assume that we program a whole system image where different partitions are included, and where kernel+dtb and rootfs are stored. We have many files to be programmed and we can use a for loop:

prog=setenv start_block 0;for i in a b c d e f g h i j k l m n o; do run select_sdhi0;setenv filenam SD_image.imga${i}.gz;printenv filenam;fatload mmc 0:1 0x48000000 $filenam;unzip 0x48000000 0x68000000;setexpr blocknum $filesize / 200;run select_emmc;mmc write 0x68000000 $start_block $blocknum;setexpr start_block $start_block + $blocknum;done;

Let's have a look at it piece by piece.

setenv start_block 0

This is support environment variable to store the sector where the current chunk needs to be programmed.

for i in a b c d e f g h i j k l m n o; do [...] done;

In this specific example the system image is split in 15 chunks (letters from "a" to "o"). These are the commands we loop thru:

run select_sdhi0

Already explained before.

setenv filenam SD_image.imga${i}.gz

We set the "filenam" environment variable combining the name with the current loop index (a, b, c, etc).

printenv filenam

This just prints it something as debug / status.

fatload mmc 0:1 0x48000000 $filenam

Current file is loaded from uSD into DDR temporary location.

unzip 0x48000000 0x68000000

Unzipped into another DDR location, 512MB apart.

setexpr blocknum $filesize / 200

Same comment as before, we need the number of 512-byte sectors.

run select_emmc

Switch to eMMC.

mmc write 0x68000000 $start_block $blocknum

Actual eMMC program operation.

setexpr start_block $start_block + $blocknum

Update the current starting block to take in account how many 512-byte sectors have already been programmed.

eMMC non-volatile registers

There are some non-volatile eMMC registers that have to be programmed once when the eMMC is virgin:

set_bootbus_width_extcsd_177_hb1=run select_emmc;mmc bootbus 0 2 0 0

Once executed this programs extcsd[177], b1 in hex, more in particular it sets BOOT_BUS_WIDTH = 0x2, (8-bit) RESET = 0x0, BOOT_MODE = 0x0.

set_part_conf_extcsd_179_hb3=mmc partconf 0 0 1 0

This programs extcsd[179], b3 in hex, basically the important part is the third parameter that basically select the first boot partition as bootable. This is the field that the internal ROM reads to understand where to take BL2 from. It is potentially very useful to implement a sort of A/B booting strategy.

Refer to JEDEC specification for more details about the extcsd registers and to this page for a detailed description of these u-boot commands.

QSPI

In case the boot media is QSPI and not eMMC boot partition, QSPI NOR flash may need to be programmed. Note that u-boot includes the support of QSPI flash only starting from the version included in VLP3.0.3.

prog_bl2_qspi=sf probe;sf erase 0 100000;run select_sdhi0;fatload mmc 0:1 0x48000000 $bl2_file;sf write 0x48000000 0 $filesize

There is not so much to comment, apart from the "0" in the last command, this is the location where BL2 has to be stored.

prog_fip_qspi=sf probe; fatload mmc 0:1 0x48000000 fip-smarc-rzg2l_pmic.bin;sf write 0x48000000 1d200 $filesize

Similarly for FIP, 0x1d200 is the location where FIP has to be stored.

Combining all steps

Of course all the described steps can be combined in one single command:

prog_all=run prog_bl2;run prog_fip;run prog_envvar;run prog;run prog_bl2_qspi;run prog_fip_qspi;run set_bootbus_width_extcsd_177_hb1;run set_part_conf_extcsd_179_hb3


  • No labels