Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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

<MCUXpresso_dir>/boards/evkmimx8mm/

2.2 Prerequisities

Install cmake

Code Block
languagebash
$ sudo apt-get install cmake

Download and install GNU-ARM bare-metal toolchain:

Code Block
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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/armgccare created:

Demo name

Image foder

Description

Link Address

TCM demo

release

release variant, no debug info, run from M4 TCM memory

0x1ffe0000

debug

debug variant, debug info included, run from M4 TCM memory

0x1ffe0000

DDR demo

ddr_release

release variant, no debug info, run from DDR memory

0x80000000

ddr_debug

debug variant, debug info included, run from DDR memory

0x80000000

FLASH demo

flash_release

release variant, no debug info, run directly from NOR flash

0x08000000

flash_debug

debug variant, debug info included, run directly from NOR flash

0x08000000

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

i.MX 8M Mini Bootloader standalone build

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

i.MX 8M Mini Bootcontainer

Bootcontainer creation tool

Linux Kernel

i.MX 8M Mini Kernel standalone build

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:

  1. ARM precompiled toolchain (by ARM company)

  2. Yocto generated SDK

3.1.1 ARM precompiled toolchain

To download, unpack and prepare ARM precompiled toolchain use these commands:

Code Block
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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
languagebash
$ cd ~/<yocto_dir>
$ source ./setup-environment.sh <build_dir>
$ bitbake -c populate_sdk fsl-image-validation-imx

Install SDK to you computer:

Code Block
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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

~/atf-imx8-family/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c

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
languagec
// ..... 
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
languagebash
$ cd ~/atf-imx8-family
$ make PLAT=imx8mm bl31

Generated file necessary for boot container creation is:

file

description

~/atf-imx8-family/build/imx8mm/release/bl31.bin

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

~/<uboot-build-dir>/spl/u-boot-spl.bin

SPL - Secondary loader, linked to TCM memory, need to activate DDR and load ATF and TPL

~/<uboot-build-dir>/u-boot-nodtb.bin

TPL - U-Boot bootloader, needed to load kernel and kernel device tree

~/<uboot-build-dir>/arch/arm/dts/imx8mm-cgtsx8m.dtb

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
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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
languagebash
$ 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
languagedts
&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
languagedts
&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

--->