i.MX 8M Mini - MCU M4 firmware guide
1. Preface
This guide describes how to build and run the firmware on ARM Cortex M4 core included in imx8m-mini SoC. It is good to start with tool MCUXpresso from NXP to design M4 firmware. This toolchain contains demos, libraries and build scripts for NXP EVK boards. As this toolset doesn't contain compiler it is necessary to use an external compiler toolchain.
To run an application with M4 core it is also necessary to update ARM Trusted Firmware ATF
and Linux Device Tree table Linux DTB
.ATF
is responsible for resource allocation (configuration which peripheral is accessible by each CPU core domain M4 and A53). To use a peripheral unit with M4 core it is necessary to attach this peripheral to M4 core domain. Then it is necessary to disable all peripherals attached to M4 domain in the Linux to prevent kernel crash (peripherals attached to M4 domain are not accessible in A53 domain).
This document is related to Congatec Yocto version: cgtimx8mm__imx-linux-zeus
With kernel 5.4.47
2. M4 - Firmware Build
2.1 SDK - MCUXpresso 2.10.0
MCUXpresso SDK is development tool-set to build firmware for micro-controllers based on Arm® Cortex®-M cores. SDK provides setups for compiler, hardware libraries, FreeRTOS operating system and examples of application for NXP development and evaluation boards. Each board support package can be found inside of the top level <MCUXpresso_dir>/boards
folder. Each supported board has its own folder with name referred as <board_name>
in this document.
MCIXpresso tool-set with documentation can be downloaded from NXP site.
NXP board | Derived Congatec Board | sub-folder name |
---|---|---|
EVK-MIMX8MM | conga-SMX8-Mini |
|
2.2 Prerequisities
Install cmake
Code Block | ||
---|---|---|
| ||
$ sudo apt-get install cmake |
Download and install GNU-ARM bare-metal toolchain:
Code Block | ||
---|---|---|
| ||
$ mkdir ~/<MCUXpresso_dir>
$ cd ~/<MCUXpresso_dir>
$ wget <https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2>
$ tar xvf gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2 |
Instal downloaded MCUXpresso tar
The SDK tools is generated by NXP download page. Select the right type of the processor and follow download instructions. Copy downloaded SDK to final folder and unpack.
Code Block | ||
---|---|---|
| ||
$ cp <download_dir>/SDK_2_10_0_EVK-MIMX8MM.tar.gz ~/<MCUXpresso_dir>
$ tar xzf SDK_2_10_0_EVK-MIMX8MM.tar.gz |
2.3 Build application
Build "Hello World" demo
All of the NXP examples are located under the following folder
~/<MCUXpresso_dir>/boards/evkmimx8mm
To show how to quickly build first demo - build of simple Hello World application is selected. This demo is linked to run from MC4 TCM memory at address 0x1ffe0000
. For detailed description of memory map see imx8mm reference manual. The demo uses UART4 to say "Hello World". How to download and run the application is described later.
To build "Hellow World" demo, follow these steps:
Code Block | ||
---|---|---|
| ||
$ cd ~/<MCUXpresso_dir>/boards/evkmimx8mm/demo_apps/hello_world
$ cd armgcc
$ export ARMGCC_DIR=~/<MCUXpresso_dir>/gcc-arm-none-eabi-10-2020-q4-major
$ ./build_all.sh > /dev/null |
Several folders in ~/<MCUXpresso_dir>/boards/evkmimx8mm/demo_apps/hello_world/armgcc
are created:
Demo name | Image foder | Description | Link Address |
---|---|---|---|
TCM demo | release | release variant, no debug info, run from M4 TCM memory |
|
debug | debug variant, debug info included, run from M4 TCM memory |
| |
DDR demo | ddr_release | release variant, no debug info, run from DDR memory |
|
ddr_debug | debug variant, debug info included, run from DDR memory |
| |
FLASH demo | flash_release | release variant, no debug info, run directly from NOR flash |
|
flash_debug | debug variant, debug info included, run directly from NOR flash |
| |
CMakeFiles | build tool files (not described in this guide) | N/A |
To run appropriate demo it is necessary to copy dedicated .bin
file to the SD card that is used for system boot.
For TCM demo copy the hello_world.bin
file located in ~/<MCUXpresso_dir>/boards/evkmimx8mm/demo_apps/hello_world/armgcc/release
to the boot media SD card to the boot
partition.
For DDR demo copy the hello_world.bin
file located in ~/<MCUXpresso_dir>/boards/evkmimx8mm/demo_apps/hello_world/armgcc/ddr_release
to the boot media SD card to the boot
partition with different name e.g hello_world_ddr.bin
.
3. Running "Hello World" demo
To run the application on ARM-Cortex M4 core it is necessary to perform additional steps, that allow M4 core access to needed resources.
3.1 Prerequisities
Resource planning is performed by ARM Trusted Firmware referenced as ATF
and Linux Device Tree setiing referenced as Linux DTB
. ATF package is a part of "Boot Container" that is used by SoC to load operating system. Linux DTB is necessary for configuration of Linux kernel device drivers. All resources needed for M4 core must be disabled in Linux.
All required packages are listed in the table bellow.
Package | Build Guide | Description |
---|---|---|
U-Boot | Das U-Boot boot loader, responsible to load ATF and Linux Kernel together with Device Tree configuration file | |
ATF | in this document | ARM Trusted Firmware - resource and security management |
MkImage | Bootcontainer creation tool | |
Linux Kernel | Linux Kernel Sources |
To build the boot container it is necessary to download (compile) and install - GNU-ARM aarch64 toolchain.
There are exists two possible sources:
ARM precompiled toolchain (by ARM company)
Yocto generated SDK
3.1.1 ARM precompiled toolchain
To download, unpack and prepare ARM precompiled toolchain use these commands:
Code Block | ||
---|---|---|
| ||
$ mkdir ~/<arm_aarch64_tool>
$ cd ~/<arm_aarch64_tool>
$ wget <https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz>
$ tar xJf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz |
3.1.2 YOCTO SDK
Yocto build tool provides own compiler toolchain that can be used out of Yocto tree. Yocto also provides necessary files to build boot container.
If you didn't build the Yocto build system before follows these steps:
First install some required packages:
Code Block | ||
---|---|---|
| ||
$ sudo apt-get update
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm sed cvs subversion coreutils texi2html docbook-utils python-pysqlite2 help2man make gcc g++ desktop-file-utils libgl1-mesa-dev libglu1-mesa-dev mercurial autoconf automake groff curl lzop asciidoc repo python3-pip |
Next install Google repo tool needed to download all necessary projects:
Code Block | ||
---|---|---|
| ||
$ mkdir -p ~/.bin
$ PATH="${HOME}/.bin:${PATH}"
$ curl <https://storage.googleapis.com/git-repo-downloads/repo> > ~/.bin/repo
$ chmod a+rx ~/.bin/repo |
And finally build the SDK:
Code Block | ||
---|---|---|
| ||
$ mkdir ~/<yocto_dir>
$ cd ~/<yocto_dir>
$ repo init -u <https://git.congatec.com/arm-nxp/imx8-family/yocto/manifest-imx8-family> \
-b cgtimx8mm__imx-linux-zeus \
-m cgtimx8mm__imx-5.4.47-2.2.0.xml
$ repo sync
$ MACHINE='imx8mm-cgt-sx8m' DISTRO=fsl-imx-wayland source imx-setup-release.sh -b <build-dir>
[ ! ] EULA accept needed for next step.
$ bitbake fsl-image-validation-imx
$ bitbake -c populate_sdk fsl-image-validation-imx |
Be aware that the build proces takes several hours.
If you have compiled Yocto image before the steps to gerenate SDK are simpler:
Code Block | ||
---|---|---|
| ||
$ cd ~/<yocto_dir>
$ source ./setup-environment.sh <build_dir>
$ bitbake -c populate_sdk fsl-image-validation-imx |
Install SDK to you computer:
Code Block | ||
---|---|---|
| ||
$ cd ~/<yocto_dir>/<build_dir>/tmp/deploy/sdk
$ ./fsl-imx-xwayland-glibc-x86_64-fsl-image-validation-imx-aarch64-imx8mm-cgt-sx8m-toolchain-5.4-zeus.sh |
Enter install folder for the SDK at your will, for this document it will be named as <~/yocto-SDK-dir>
.
Note: If you are to use a system folder (i.e. /opt
) call this script with sudo
.
3.2 ATF Update
ARM Trusted Firmware is a part of standard boot-container supproted by NXP and Congatec.
First download and deploy source code for ATF.
Code Block | ||
---|---|---|
| ||
$ git clone git@git.congatec.com:arm-nxp/imx8-family/atf-imx8-family.git
$ cd atf-imx8-family
$ git checkout --track cgtimx8mm__imx_5.4.47_2.2.0 |
Prepare toolchain to be used for this build:
Precompiled toolchain:
Code Block | ||
---|---|---|
| ||
$ export PATH=${PATH}:~/<arm_aarch64_tool>/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-none-linux-gnu-
|
Or Yocto generated toolchain:
Code Block | ||
---|---|---|
| ||
$ cd <yocto_SDK_dir>
$ source environment-setup-aarch64-poky-linux |
Next it is necessary to update source code file responsible for resource and security setting:
file | description |
---|---|
| source file with board setup code |
ATF documentation can be found on ATF-A projetc documentation pages.
3.2.1 Example how to enable UART4 for M4 core domain:
Find this piece of code in the file imx8mm_bl31_setup.c
Code Block | ||
---|---|---|
| ||
// .....
static const struct imx_rdc_cfg rdc[] = {
/* Master domain assignment */
RDC_MDAn(RDC_MDA_M4, DID1),
/* peripherals domain permission */
RDC_PDAPn(RDC_PDAP_UART4, D0R | D0W),
RDC_PDAPn(RDC_PDAP_UART2, D0R | D0W),
/* memory region */
/* Sentinel */
{0},
// ..... |
and change it to:
Code Block |
---|
// .....
static const struct imx_rdc_cfg rdc[] = {
/* Master domain assignment */
RDC_MDAn(RDC_MDA_M4, DID1),
/* peripherals domain permission */
RDC_PDAPn(RDC_PDAP_UART4, D1R | D1W), // UART4 is attached to domain 1 (M4 core)
RDC_PDAPn(RDC_PDAP_UART2, D0R | D0W),
/* memory region */
/* Sentinel */
{0},
// ..... |
next build the ATF:
Code Block | ||
---|---|---|
| ||
$ cd ~/atf-imx8-family
$ make PLAT=imx8mm bl31 |
Generated file necessary for boot container creation is:
file | description |
---|---|
| ATF binary image linked to OCRAM memory |
3.3 U-Boot
Build appropriate U-Boot for your bootcontainer. Follows instructions how to build U-Boot for SD card or onboard NOR FLASH in guide "i.MX 8M Mini Bootloader standalone build".
NOTE: supposed that cross-compiler toochain is set as it is described in section 3.2 ATF Update
Configurations for U-Boot build:
Configuration | Description |
---|---|
flash_sx8m | Uboot linked for SD card |
flash_sx8m_flexspi | U-Boot linked for onboard NOR Flash |
Generated files necessary for boot container creation are:
file | description |
---|---|
| SPL - Secondary loader, linked to TCM memory, need to activate DDR and load ATF and TPL |
| TPL - U-Boot bootloader, needed to load kernel and kernel device tree |
| U-Boot device tree |
NOTE: naming scheme is the same for both U-Boot versions (SD or NOR Flash).
3.4 Bootcontainer
Boot container is a small binary file that is recognized and loaded by the SoC internal ROM code. ROM code check several supported boot devices.
To prepare boot container the U-Boot from Yocto can be used with limitation that Congatec Yocto build environment provides U-Boot dedicated for SD card deployment only. To obtain U-Boot dedicated for internal NOR flash it is necessary to build it from source codes.
The guide how to prepare boot container binary file is on i.MX 8M Mini Bootcontainer.
First prepare boot container build tool:
Code Block | ||
---|---|---|
| ||
$ git clone <https://git.congatec.com/arm-nxp/imx8-family/misc/mkimage-imx8-family.git>
$ cd mkimage-imx8-family
$ git checkout rel_cgtsx8m_20-06-16-0 |
next copy files in the bellow to the folder ~/mkimage-imx8-family/iMX8M/
:
UBoot:
~/<uboot-build-dir>/spl/u-boot-spl.bin
~/<uboot-build-dir>/u-boot-nodtb.bin
~/<uboot-build-dir>/arch/arm/dts/imx8mm-cgtsx8m.dtb
ATF:
~/atf-imx8-family/build/imx8mm/release/bl31.bin
DDR training binaries
~/<yocto_dir>/<build_dir>/tmp/deploy/images/imx8mm-cgt-sx8m/imx-boot-tools/lpddr4_pmu_train_1d_dmem.bin
~/<yocto_dir>/<build_dir>/tmp/deploy/images/imx8mm-cgt-sx8m/imx-boot-tools/lpddr4_pmu_train_1d_imem.bin
~/<yocto_dir>/<build_dir>/tmp/deploy/images/imx8mm-cgt-sx8m/imx-boot-tools/lpddr4_pmu_train_2d_dmem.bin
~/<yocto_dir>/<build_dir>/tmp/deploy/images/imx8mm-cgt-sx8m/imx-boot-tools/lpddr4_pmu_train_2d_imem.bin
Finaly create boot conteiner image:
Code Block |
---|
make SOC=iMX8MM <Make Image Target> |
Where <Make Image Target>
is:
Boot Device | Target |
---|---|
SD Card | flash_sx8m |
NOR Flash | flash_sx8m_flexspi |
Resulting file flash.bin
is located in the folder ~/mkimage-imx8-family/iMX8M/
3.4.1 Install boot container - SD card build
SD card boot container image can be coppied to SD card by dd
commnad.
Code Block |
---|
$ sudo dd if=flash.bin bs=1k seek=33 of=/dev/sd<...> |
3.4.2 Install boot container - NOR Flash build
Copy NOR flash version of the boot container to SD card to "boot" partition
Code Block |
---|
$ cp flash.bin /media/<user>/boot/flash_nor.bin |
Insert SD card to the board and break boot sequence in the U-Boot (just by hitting some key). Then load the boot container binary to the RAM and flash it to the NOR flash:
Code Block |
---|
uboot:> sf probe
uboot:> sf erase 0x0 0x700000
....
uboot:> fatload mmc 1:1 0x40000000 flash_nor.bin
<size_bytes_decimal>
uboot:> sf write 0x40000000 0x0 <size_bytes_hex> |
NOTE: fatload shows the size in bytes in decimal format, to use this in sf write command it is necessary to convert this number to hexadecimal format
3.5 Linux Device Tree
To prevent Linux kernel to access resources attached to the M4 core it is necessary to disable these devices in the Kernel Device Tree configuration file. Kernel sources can be downloaded from Yocto tree or directly from Congatec GIT.
To use Linux Kernel from Congatec Yocto use these commands:
Code Block | ||
---|---|---|
| ||
$ mkdir ~/<kernel_dir>
$ cp -R ~/<yocto_dir>/<build_dir>/tmp/work/imx8mm_cgt_sx8m-poky-linux/linux-congatec-sx8m/5.4-r0/git/* ~/<kernel_dir> |
Or you can get kernel source from Congatec GIT repository:
Code Block |
---|
$ git clone <https://git.congatec.com/arm-nxp/imx8-family/kernel-imx8-family.git> ~/<kernel_dir>
$ cd ~/<kernel_dir>
$ git checkout rel_cgtsx8m_21-03-16-0 |
Now edit DTB located at: ~<kernel_dir>/arch/arm64/boot/dts/congatec/imx8mm-cgtsx8m.dts
Finaly compile DTB NOTE: supposed that cross-compiler toochain is set as it is described in section 3.2 ATF Update
Code Block | ||
---|---|---|
| ||
$ cd ~/<kernel_dir>
$ make sx8m_defconfig
$ make dtbs |
Copy created DTB file to the SD card, partition /boot
(as a replacement of old DTB file)
Code Block | ||
---|---|---|
| ||
$ cp ~/<kernel_dir>/arch/arm64/boot/dts/congatec/imx8mm-cgtsx8m.dtb /media/<user>/boot |
3.5.1 Example how to remove UART4 from kernel DTS:
Open file ~<kernel_dir>/arch/arm64/boot/dts/congatec/imx8mm-cgtsx8m.dts
in some text editor and find the section:
Code Block | ||
---|---|---|
| ||
&uart4 { /* SER1 */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart4>;
assigned-clocks = <&clk IMX8MM_CLK_UART4>;
assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
status = "okay";
}; |
and change field status - to disabled
Code Block | ||
---|---|---|
| ||
&uart4 { /* SER1 */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart4>;
assigned-clocks = <&clk IMX8MM_CLK_UART4>;
assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_80M>;
status = "disabled";
}; |
3.6 Download and Run demo application with U-Boot
Connect serial cable to debug console on the board and open your preferred serial terminal for the serial devices, setting the speed to 115200 bps, 8 data bits, 1 stop bit (115200, 8N1), no parity, then power on the board.
Connect another serial cable to SER1 serial port on the SEVAL carrier board and open another terminal application on the PC. Configure the terminal with this setting:
115200
No parity
8 data bits
1 stop bit
Power on the board and hit any key to stop autoboot in the terminal, then enter to U-Boot command line mode. You can then write the image and run it from TCM or DRAM with the following commands:
a. If the hello_world.bin is made from the debug/release target, which means the binary file will run at TCM, use the following commands to boot:
Code Block |
---|
$ fatload mmc 1:1 0x48000000 hello_world.bin
$ cp.b 0x48000000 0x7e0000 0x20000
$ bootaux 0x7e0000 |
b. If the hello_world.bin is made from the ddr_debug/ddr_release target, which means the binary file runs at DRAM, use the following commands:
Code Block |
---|
• fatload mmc 1:1 0x80000000 hello_world.bin
• dcache flush
• bootaux 0x80000000 |
<!---
c. If the hello_world.bin is made from the flash_debug/flash_releasetarget, which means the binary file runs at nor_flash, use the following commands:
Code Block |
---|
• fatload mmc 1:1 0x80000000 flash.bin
• dcache flush
• sf probe
• sf erase 0 0x20000
• sf write 0x80000000 0 0x20000
• bootaux 0x8000000 |
--->