1. Introduction[edit source]
The coprocessor firmware can be loaded and started:
- either by the second stage bootloader, U-Boot (see Boot_chain_overview for details) or
- by the Linux® kernel (see Linux_remoteproc_framework_overview for details)
This article explains how the coprocessor firmware is loaded by U-Boot and started before the Linux kernel.
2. Location of the coprocessor firmware[edit source]
U-Boot searches and loads the required binaries in the first bootable partition (generic DISTRO configuration) which is bootfs in the OpenSTLinux distribution (see STM32MP15_Flash_mapping), so the coprocessor firmware must be installed in that bootfs partition. The simplest way to do it consists in copying the firmware from the rootfs partition to the bootfs partition as follows:
mount /dev/mmcblk0p4 /boot cp rproc-m4-fw.elf /boot/ sync
As an alternative method, you can use the Eclipse IDE, or transfer the firmware over the serial console or over the network.
Note: The default name of the firmware used in this WIKI is rproc-m4-fw.elf.
3. Starting the coprocessor firmware[edit source]
U-Boot can boot the coprocessor before the kernel (coprocessor early boot) with remoteproc uclass . Several methods are possible:
- Manual start by using rproc commands
- Automatic start, at each boot by using
- the bootcmd (needing U-Boot recompilation)
- a generic DISTRO boot script
- the FIT image
3.1. Manual start[edit source]
You can load and start the coprocessor firmware by using the rproc command in the U-Boot console (to access to the U-boot console, press any key during the U-Boot execution).
rproc rproc - Control operation of remote processors in an SoC Usage: rproc [init|list|load|start|stop|reset|is_running|ping] Where: [addr] is a memory address <id> is a numerical identifier for the remote processor provided by 'list' command. Note: Remote processors must be initalized prior to usage Note: Services depend on the driver capability 'list' command shows the capability of each device Subcommands: init - Enumerates and initializes the remote processors list - lists available remote processors load <id> [addr] [size]- Loads the remote processor with image stored at address [addr] in memory start <id> - Starts the remote processor(must be loaded) stop <id> - Stops the remote processor reset <id> - Resets the remote processor is_running <id> - Reports if the remote processor is running ping <id> - Pings the remote processor for communication
In this example, the firmware is loaded from an SD card into RAM (at ${kernel_addr_r}), and then launched.
ext4load mmc 0:4 ${kernel_addr_r} rproc-m4-fw.elf -> SD card is mmc 0, bootfs is ext4 partition number 4) rproc init -> initializes all coprocessors rproc load 0 ${kernel_addr_r} ${filesize} -> loads firmware for coprocessor 0 (code part found in .elf) rproc start 0 -> starts coprocessor 0
You can then resume the normal boot process:
run bootcmd
3.2. Automatic start[edit source]
3.2.1. Start from the bootcmd[edit source]
You can update the bootcmd which is exectued automatically: modify CONFIG_EXTRA_ENV_SETTINGS in include/configs/stm32mp1.h and then recompile U-Boot.
For example, to boot a firmware from an SD card, proceed as follows:
#define CONFIG_EXTRA_ENV_SETTINGS \ "stdin=serial\0" \ "stdout=serial\0" \ "stderr=serial\0" \ ... BOOTENV \ "m4fw_name=rproc-m4-fw.elf\0" \ "m4fw_addr=${kernel_addr_r}\0" \ "boot_m4fw=rproc init; rproc load 0 ${m4fw_addr} ${filesize}; rproc start 0\0" \ "boot_m4_mmc0=if ext4load mmc 0:4 ${m4fw_addr} ${m4fw_name} ; then run boot_m4fw; fi;\0" "bootcmd=run boot_m4_mmc0; run bootcmd_mmc0\0"
Note: It is recommended to check STM32MP15_U-Boot for compilation.
3.2.2. Start from a generic DISTRO boot script[edit source]
Without U-boot recompilation, you can also use a DISTRO boot script boot.scr.uimg to automatically load and run the firmware.
For example, use the following script to boot from mmc 0, boot.scr.cmd:
env set m4fw_name "rproc-m4-fw.elf" env set m4fw_addr ${kernel_addr_r} #load M4 firmware if ext4load mmc 0:4 ${m4fw_addr} ${m4fw_name} then rproc init rproc load 0 ${m4fw_addr} ${filesize} rproc start 0 fi #load kernel and device tree ext4load mmc 0:4 ${kernel_addr_r} uImage ext4load mmc 0:4 ${fdt_addr_r} ${board_name}.dtb # start kernel env set bootargs root=/dev/mmcblk0p6 rootwait rw console=ttySTM0,115200 bootm ${kernel_addr_r} - ${fdt_addr_r}
Then generate the associated image using mkimage U-Boot tool:
mkimage -T script -C none -A arm -d boot.scr.cmd boot.scr.uimg
Lastly, install boot.scr.uimg in the bootfs partition (following the same procedure used for coprocessor firmware)
sudo cp boot.scr.uimg /media/$USER/bootfs sync
sudo rm -r /media/$USER/bootfs/extlinux sync
3.2.3. Start from the FIT image[edit source]
The coprocessor firmware can also be included in the new U-Boot image format, Flattened uImage Tree (FIT) . This firmware is then automatically loaded when it is detected by U-Boot.
Refer to chapter 'Coprocessor firmware' in board/st/stm32mp1/README : it contains an example of '.its' file, <U-Boot directory>/board/st/stm32mp1/fit_copro_kernel_dtb.its, and shows how to generate the FIT with U-Boot mkimage tool:
mkimage -f fit_copro_kernel_dtb.its fit_copro_kernel_dtb.itb
You can load the generated FIT using:
- 'bootm' command (see doc/uImage.FIT/command_syntax_extensions.txt )
- extlinux.conf in bootfs in extlinux directory to automatically load the FIT by generic DISTRO,
for example: < U-Boot directory>/board/st/stm32mp1/extlinux.conf
To go deeper, read:
- doc/README.pxe
- doc/uImage.FIT/howto.txt
- support of firmware in FIT is done in board_stm32copro_image_process() function in board/st/stm32mp1/stm32mp1.c associated to image type IH_TYPE_STM32COPRO.
4. Synchronizing the remote firmware with Linux[edit source]
The STM32MPU Embedded Software distribution provides the ability to detect and manage a firmware loaded by U-Boot thanks to the remoteproc Linux framework.
The developer must pay attention to how he implements the Arm Cortex-M4 firmware if the RPMsg is used to communicate with Linux. In this case a synchronization is required. The Arm Cortex-M4 core has to wait until Linux is booted to start RPMsg communications. When Linux is ready, the Linux kernel automatically updates the vdev status in the resource table, and sends a signal to the Arm Cortex-M4 core using the IPCC peripheral.
Two methods can be implemented to wait for the synchronization:
- Blocking method: the firmware is blocked on MX_OPENAMP_Init call (by the rproc_virtio_wait_remote_ready function) until the Linux kernel is ready to communicate (update of the vdev status in the resource table).
- Non-blocking method: when it is ready to communicate, the Linux kernel generates an interrupt towards the Arm Cortex-M4 core using the IPCC peripheral. This interrupt can be used by the Arm Cortex-M4 firmware to initialize the OpenAMP middleware and start the RPMsg protocol.