If you've been following me for very long at all, you'll know that I'm a big fan of the Zynqberry and ZynqberryZero FPGA development boards. One of my not-so-favorite parts of the Zynqberry boards is that the CLG225 package Zynq FPGA chips they use do not support booting from an SD Card directly. Thus you have to perform the primary boot (Zynq FSBL) and the secondary boot (u-boot) from the QSPI. Therefore, the boot binary (BOOT.BIN) needs to be programmed into the QSPI flash of the Zynqberry and ZynqberryZero.
With u-boot running from the QSPI flash on this FPGA board, it means that the u-boot environment must be configured to now load the kernel image and device tree from a different location which is the SD card. In all of my past projects, I've always made these updates to the u-boot environment from the u-boot command prompt by halting the boot process to access it then issuing the following commands:
Zynq> setenv cp_kernel2ram 'fatload mmc 0 ${netstart} ${kernel_img}'
Zynq> setenv cp_dtb2ram 'fatload mmc 0 ${dtbnetstart} ${dtb_img}'
Zynq> setenv default_bootcmd 'run cp_kernel2ram && run cp_dtb2ram && bootm ${netstart} - ${dtbnetstart}'
Zynq> setenv bootargs 'console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 ru rootwait'
Zynq> saveenv
This isn't a huge deal, but it does get annoyingly repetitive, so I finally decided to figure out how to configure these u-boot environment variables into the PetaLinux project to save myself this step in future projects.
Modify Environment Variables in U-Boot RecipePetaLinux generates a u-boot configuration from the settings specified in the system configuration editor (petalinux-config) and the settings specified in the u-boot configuration editor (petalinux-config -c -u-boot). This configuration is written to the file platform-auto.h located in /project-spec/meta-plnx-generated/recipes-bsp/u-boot/configs/ of the PetaLinux project.
Given that I know I need to modify bootargs, cp_kernel2ram, cp_dtb2ram, and default_bootcmd, I simply searched for them in platform-auto.h to find which CONFIG_ option each were defined under. For cp_kernel2ram, cp_dtb2ram, and default_bootcmd, they are all defined under the CONFIG_EXTRA_ENV_SETTINGS option section.
Boot arguments, bootargs, is actually not directly saved to platform-auto.h, thus we have to specify it in the device tree which I'll do in the next step.
The platform-auto.h file is not user-configurable. It is regenerated every time the petalinux-config or petalinux-config -c -u-boot commands are run. Thus for any user modifications to be persistent, they must be done instead in the platform-top.h file located in /project-spec/meta-user/recipes-bsp/u-boot/files/.
Copy the entire section of #define CONFIG_EXTRA_ENV_SETTINGS from /project-spec/meta-plnx-generated/recipes-bsp/u-boot/configs/platform-auto.h to /project-spec/meta-user/recipes-bsp/u-boot/files/platform-top.h and modify cp_kernel2ram, cp_dtb2ram, and default_bootcmd to the Zynqberry specific values:
cp_kernel2ram=fatload mmc 0 ${netstart} ${kernel_img}
cp_dtb2ram=fatload mmc 0 ${dtbnetstart} ${dtb_img}
default_bootcmd=run cp_kernel2ram && run cp_dtb2ram && bootm ${netstart} - ${dtbnetstart}
Here's what the resulting platform-top.h file should look like:
#include <configs/platform-auto.h>
#define CONFIG_SYS_BOOTM_LEN 0xF000000
#define DFU_ALT_INFO_RAM \
"dfu_ram_info=" \
"setenv dfu_alt_info " \
"image.ub ram $netstart 0x1e00000\0" \
"dfu_ram=run dfu_ram_info && dfu 0 ram 0\0" \
"thor_ram=run dfu_ram_info && thordown 0 ram 0\0"
#define DFU_ALT_INFO_MMC \
"dfu_mmc_info=" \
"set dfu_alt_info " \
"${kernel_image} fat 0 1\\\\;" \
"dfu_mmc=run dfu_mmc_info && dfu 0 mmc 0\0" \
"thor_mmc=run dfu_mmc_info && thordown 0 mmc 0\0"
/* Extra U-Boot Env settings */
#define CONFIG_EXTRA_ENV_SETTINGS \
SERIAL_MULTI \
CONSOLE_ARG \
DFU_ALT_INFO_RAM \
DFU_ALT_INFO_MMC \
PSSERIAL0 \
"bootenv=uEnv.txt\0" \
"importbootenv=echo \"Importing environment from SD ...\"; " \
"env import -t ${loadbootenv_addr} $filesize\0" \
"loadbootenv=load mmc $sdbootdev:$partid ${loadbootenv_addr} ${bootenv}\0" \
"sd_uEnvtxt_existence_test=test -e mmc $sdbootdev:$partid /uEnv.txt\0" \
"uenvboot=" \
"if run sd_uEnvtxt_existence_test; then " \
"run loadbootenv; " \
"echo Loaded environment from ${bootenv}; " \
"run importbootenv; " \
"fi; " \
"if test -n $uenvcmd; then " \
"echo Running uenvcmd ...; " \
"run uenvcmd; " \
"fi\0" \
"autoload=no\0" \
"sdbootdev=0\0" \
"clobstart=0x10000000\0" \
"netstart=0x10000000\0" \
"dtbnetstart=0x23fff000\0" \
"loadaddr=0x10000000\0" \
"bootsize=0x500000\0" \
"bootstart=0x0\0" \
"boot_img=BOOT.BIN\0" \
"sd_update_boot=echo Updating boot from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${boot_img} && run install_boot\0" \
"install_boot=sf probe 0 && sf erase ${bootstart} ${bootsize} && " \
"sf write ${clobstart} ${bootstart} ${filesize}\0" \
"bootenvsize=0x20000\0" \
"bootenvstart=0x500000\0" \
"eraseenv=sf probe 0 && sf erase ${bootenvstart} ${bootenvsize}\0" \
"jffs2_img=rootfs.jffs2\0" \
"sd_update_jffs2=echo Updating jffs2 from SD; mmcinfo && fatload mmc ${sdbootdev}:1 ${clobstart} ${jffs2_img} && run install_jffs2\0" \
"install_jffs2=sf probe 0 && sf erase ${jffs2start} ${jffs2size} && " \
"sf write ${clobstart} ${jffs2start} ${filesize}\0" \
"kernel_img=image.ub\0" \
"install_kernel=mmcinfo && fatwrite mmc ${sdbootdev} ${clobstart} ${kernel_img} ${filesize}\0" \
"cp_kernel2ram=fatload mmc 0 ${netstart} ${kernel_img}\0" \
"dtb_img=system.dtb\0" \
"install_dtb=mmcinfo && fatwrite mmc ${sdbootdev} ${clobstart} ${dtb_img} ${filesize}\0" \
"cp_dtb2ram=fatload mmc 0 ${dtbnetstart} ${dtb_img}\0" \
"loadbootenv_addr=0x00100000\0" \
"fault=echo ${img} image size is greater than allocated place - partition ${img} is NOT UPDATED\0" \
"test_crc=if imi ${clobstart}; then run test_img; else echo ${img} Bad CRC - ${img} is NOT UPDATED; fi\0" \
"test_img=setenv var \"if test ${filesize} -gt ${psize}\\; then run fault\\; else run ${installcmd}\\; fi\"; run var; setenv var\0" \
"default_bootcmd=run cp_kernel2ram && run cp_dtb2ram && bootm ${netstart} - ${dtbnetstart}\0" \
""
/*Required for uartless designs */
#ifndef CONFIG_BAUDRATE
#define CONFIG_BAUDRATE 115200
#ifdef CONFIG_DEBUG_UART
#undef CONFIG_DEBUG_UART
#endif
#endif
/*Dependencies for ENV to be stored in EEPROM. Ensure environment fits in eeprom size*/
#ifdef CONFIG_ENV_IS_IN_EEPROM
#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
#define CONFIG_SYS_I2C_EEPROM_ADDR 0x54
#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 4
#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
#define CONFIG_SYS_EEPROM_SIZE 1024 /* Bytes */
#define CONFIG_SYS_I2C_MUX_ADDR 0x74
#define CONFIG_SYS_I2C_MUX_EEPROM_SEL 0x4
#endif
Save and close platform-top.h
Modify Boot Arguments in Device TreeBoot arguments, bootargs, is one of the final commands to be run by u-boot that specifies exactly where the root filesystem is. While the bootargs variable is actually derived from a few different configurations from the platform-auto.h file, trying to modify each of them to get the overall modification I wanted (which is simply to add the root filesystem type) got too convoluted in my opinion. So, since the device tree be loaded by this point in the boot process that bootargs is being called by u-boot, I decided to simply specify my desired bootargs there using the chosen node.
In the user-defined device tree file system-user.dtsi located in /project-spec/meta-user/recipes-bsp/device-tree/files/ add the Zynqberry bootargs using the chosen node:
chosen {
bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 ru rootwait";
stdout-path = "serial0:115200n8";
};
Save and close system-user.dtsi.
Rebuild PetaLinux ProjectTo make sure the existing u-boot files generated from the last project build are actually updated, it's more effective to delete them by cleaning the PetaLinux project as a whole:
petalinux-build -x mrproper --force
Then build the new u-boot:
petalinux-build -c u-boot
And rebuild the whole PetaLinux project:
petalinux-build
Then to generate a new boot binary image for the project, the --force flag has to be used:
petalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --fpga ./images/linux/system.bit --u-boot --force
Reflash the Zynqberry/ZynqberryZero QSPI with the new BOOT.BIN using Vitis and replace the device tree and kernel images on the SD card. Then you're good to go! This modification can be done to any of your existing PetaLinux projects for the Zynqberry/ZynqberryZero. So far, this particular u-boot modification works in PetaLinux 2018.3 and 2019.2, and I'm working on updating my entire Zynqberry project to 2020.2 and 2021.1, which I'll post when working!
Comments