Building a Linux system for the STM32MP1: basic system

As we announced recently, we are going to publish a series of blost post that describes how to build an embedded Linux device based on the STM32MP1 platform, using the Buildroot build system. In this first article, we are going to see how to create a basic Linux system, with minimal functionality. The hardware platform used in these articles is the STM32MP157-DK2.

What is Buildroot?

A Linux system is composed of a potentially large number of software components coming from different sources:

  • A bootloader, typically U-Boot, responsible for doing some minimal HW initialization, loading the Linux kernel and starting it
  • The Linux kernel itself, which implements features such as process management, memory management, scheduler, filesystems, networking stack and of course all device drivers for your hardware platform
  • User-space libraries and applications coming from the open-source community: command line tools, graphical libraries, networking libraries, cryptographic libraries, and more.
  • User-space libraries and applications developed internally, implementing the “business logic” of the embedded system

In order to assemble a Linux system with all those software components, one typically has two main choices:

  • Use a binary distribution, like Debian, Ubuntu or Fedora. Several of these distributions have support for the ARMv7 architecture. The main advantage of this solution is that it is easy: these binary distributions are familiar to most Linux users, they have a nice and easy-to-use package management system, all packages are pre-compiled so it is really fast to generate a Linux system. However, Linux systems generated this way are typically difficult to customize (software components are pre-built, so you cannot easily tweak their configuration to your needs) and difficult to optimize (in terms of footprint or boot time).
  • Use a build system, like Buildroot or Yocto/OpenEmbedded. These build systems build an entire Linux system from source code, which means that it can be highly customized and optimized to your needs. Of course, it is less simple than using a binary distribution and because you are building all components from source code, a non-negligible amount of CPU time will be spent on compiling code.

BuildrootIn this series of blog post, we have chosen to use Buildroot, which is an easy-to-use build system, which is a good match for engineers getting started with embedded Linux. For more general details about Buildroot, you can read the freely available training materials of our Embedded Linux development with Buildroot training course.

Buildroot is a set of Makefiles and script that automates the process of download the source code of the different software components, extract them, configure them, build them and install them. It ultimately generates a system image that is ready to be flashed, and which typically contains the bootloader, the Linux kernel image and the root filesystem. It is important to understand that Buildroot itself does not contain the source code for Linux, U-Boot or any other component: it is only a set of scripts/recipes that describes where to download the source code from, and how to build it.

Principle of an embedded Linux build system

Building the minimal system with Buildroot

Let’s started by getting the source of Buildroot from its upstream Git repository:

git clone git://git.buildroot.net/buildroot
cd buildroot

Starting a Buildroot configuration is then typically done by running make menuconfig, and then selecting all the relevant options for your system. Here, we are instead going to use a pre-defined configuration that we created for the STM32MP157-DK2 platform. This pre-defined configuration has been submitted to the upstream Buildroot project, but has not yet been merged as of this writing, so we’ll use an alternate Git branch:

git remote add tpetazzoni https://github.com/tpetazzoni/buildroot.git
git fetch tpetazzoni
git checkout -b stm32mp157-dk2 tpetazzoni/2019.02/stm32mp157-dk

The 2019.02/stm32mp157-dk branch in your author’s Buildroot Git repository is based on upstream Buildroot 2019.02.x branch and contains 4 additional patches needed to support the STM32MP157-DK2 platform.

Let’s continue by telling Buildroot to load the pre-defined configuration for the STM32MP157-DK2:

make stm32mp157_dk_defconfig

We could start the build right away, as this configuration works fine, but to illustrate how to modify the configuration (and speed up the build!) we will adjust one aspect of the system configuration. To do so, let’s run Buildroot’s menuconfig. People who have already configured the Linux kernel should be familiar with the tool, as it is the exact same configuration utility.

make menuconfig

At this point, if the command fails due to the ncurses library being missing, make sure to install the libcnurses-dev or ncurses-devel package on your Linux distribution (the exact package name depends on the distribution you’re using).

Once in menuconfig, go to the Toolchain sub-menu. By default the Toolchain type is Buildroot toolchain. Change it to External toolchain by pressing the Enter key. When Buildroot toolchain is selected, Buildroot builds its own cross-compiler, which takes quite some time. Selecting External toolchain tells Buildroot to use a pre-existing cross-compiler, which in our case is the one provided by ARM for the ARMv7 architecture.

Exit menuconfig and save the configuration. It is now time to start the build by running make. However, your author generally likes to keep the output of the build in a log file, using the following incantation:

make 2>&1 | tee build.log

Now that Buildroot starts by checking if your system has a number of required packages installed, and will abort if not. Please follow section System requirements > Mandatory packages of the Buildroot manual to install all the appropriate dependencies. Restart the make command once all dependencies have been installed.

The build process took 10 minutes on your author’s machine. All the build output is conveniently grouped in the sub-directory named output/, in which the most important results are in output/images/:

  • output/images/zImage is the Linux kernel image
  • output/images/stm32mp157c-dk2.dtb is the Device Tree Blob, i.e the piece of data that describes to the Linux kernel the hardware it is running on. We’ll talk more about Device Tree in the second blog post of this series
  • output/images/rootfs.{ext4,ext2} is the image of the root filesystem, i.e the filesystem that contains all the user-space libraries and applications. It’s using the ext4 filesystem format, which is the de-facto standard filesystem format in Linux for block storage.
  • output/images/u-boot-spl.stm32 is the first stage bootloader
  • output/images/u-boot.img is the second stage bootloader
  • output/images/sdcard.img is a complete, ready-to-use SD card image, which was generated from the previous images

Flashing and testing the system

First things first, we’ll need to write sdcard.img to a microSD card:

sudo dd if=output/images/sdcard.img of=/dev/mmcblk0 bs=1M conv=fdatasync status=progress

Of course, make sure that, on your system, the microSD card is really identified as /dev/mmcblk0. And beware that all the data on your microSD card will be lost!

Insert the microSD card in the microSD card connector of the STM32MP157-DK2 board, i.e connector CN15.

Connect a USB to micro-USB cable between your PC and the connector labeled ST-LINK CN11 on the board. A device called /dev/ttyACM0 will appear on your PC, through which you’ll be able to access the board’s serial port. Install and run a serial port communication program on your PC, your author’s favorite is the very minimalistic picocom:

picocom -b 115200 /dev/ttyACM0

Finally, power up the board by connecting a USB-C cable to connector PWR_IN CN6. You should then see a number of messages on the serial port, all the way up to Buildroot login:. You can then login with the root user, no password will be requested.

STM32MP157-DK2 in situation

How is the system booting ?

Let’s look at the main steps of the boot process, by studying the boot log visible on the serial port:

U-Boot SPL 2018.11-stm32mp-r2.1 (Apr 24 2019 - 10:37:17 +0200)

This message is printed by the first stage bootloader, i.e the code contained in the file u-boot-spl.stm32, compiled as part of the U-Boot bootloader. This first stage bootloader is directly loaded by the STM32MP157 system-on-chip. This first stage bootloader must be small enough to fit inside the STM32MP157 internal memory.

U-Boot 2018.11-stm32mp-r2.1 (Apr 24 2019 - 10:37:17 +0200)

This message is printed by the second stage bootloader, which was loaded from storage into external memory by the first stage bootloader. This second stage bootloader is the file u-boot.img, which was also compiled as part of the U-Boot bootloader.

Retrieving file: /boot/zImage
Retrieving file: /boot/stm32mp157c-dk2.dtb

These messages are printed by the second stage bootloader: we see it is loading the Linux kernel image (file zImage) and the Device Tree Blob describing our hardware platform (file stm32mp157c-dk2.dtb). It indicates that U-Boot has loaded both files into memory: it is now ready to start the Linux kernel.

Starting kernel ...

This is the last message printed by U-Boot before jumping into the kernel.

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.19.26 (thomas@windsurf) (gcc version 8.2.1 20180802 (GNU Toolchain for the A-profile Architecture 8.2-2018.11 (arm-rel-8.26))) #1 SMP PREEMPT Wed Apr 24 10:38:00 CEST 2019

And immediately after that, we have the first messages of the Linux kernel, showing the version of Linux and the date/time it was built. Numerous other kernel messages are then displayed, until:

[    3.248315] VFS: Mounted root (ext4 filesystem) readonly on device 179:4.

This message indicates that the kernel has mounted the root filesystem. After this point, the kernel will start the first user-space process, so the next messages are user-space services being initialized:

Starting syslogd: OK
[...]
Welcome to Buildroot
buildroot login: 

Until we reach a login prompt.

Exploring the system

After logging in as root, you have access to a regular Linux shell, with most basic Linux commands available. You can run ps to see the processes, run ls / to see the contents of the root filesystem, etc.

You can also play a bit with the hardware, for example to turn on and off one of the LEDs of the board:

echo 255 > /sys/class/leds/heartbeat/brightness
echo 0 > /sys/class/leds/heartbeat/brightness

Understanding the Buildroot configuration

So far, we have used a pre-defined Buildroot configuration, without really understanding what it does and how it built this basic system for our board. So let’s go back in make menuconfig and see how Buildroot was configured.

In the Target options menu, obviously the ARM Little Endian architecture was chosen, and more specifically Cortex-A7 was chosen as the Target Architecture Variant. Indeed the entire Linux system runs on the Cortex-A7 cores.

In the Build options menu, nothing was changed from the default values.

In the Toolchain menu, we previously modified to use an External toolchain to use a pre-existing cross-compiler and save on build time. All other options were kept as their default.

In the System configuration menu, we defined the following things:

  • Root filesystem overlay directories is set to board/stmicroelectronics/stm32mp157-dk/overlay/. This option tells Buildroot that the contents of the board/stmicroelectronics/stm32mp157-dk/overlay/ directory must be copied into the root filesystem at the end of the build. It allows to add custom files to the root filesystem.
  • Custom scripts to run after creating filesystem images is set to support/scripts/genimage.sh and the related option Extra arguments passed to custom scripts is set to -c board/stmicroelectronics/stm32mp157-dk/genimage.cfg. This tells Buildroot to call this genimage.sh script at the very end of the build: its purpose is to generate the final SD card image we have used.

In the Kernel menu, we have obviously configured which Linux kernel version and configuration should be used:

  • We are downloading the Linux kernel source code as a tarball from Github, using a custom Buildroot macro called github. Based on this information, Buildroot will go to the Git repository at https://github.com/STMicroelectronics/linux/, and get the kernel version identified by the tag v4.19-stm32mp-r1.2
  • Configuration file path is set to board/stmicroelectronics/stm32mp157-dk/linux.config. This is the file that contains the kernel configuration. We have prepared a custom kernel configuration to have a simple but working kernel configuration. Of course, it can be adjusted to your needs, as we will demonstrate in the next blog post.
  • We enabled the option Build a Device Tree Blob (DTB) and set In-tree Device Tree Source file names to stm32mp157c-dk2. This tells Buildroot to build and install the Device Tree Blob that matches our hardware platform.
  • Finally, we enabled Install kernel image to /boot in target, so that the kernel image and the Device Tree blob are installed inside the /boot directory in the root filesystem. Indeed, our U-Boot configuration will load them from here (see below).

In the Target packages menu, we have kept the default: only the BusyBox package is enabled. BusyBox is a very popular tool in the embedded Linux ecosystem: it provides a lightweight replacement for a Linux shell and most common Linux command line tools (cp, mv, ls, vi, wget, tar, and more). Our basic system in fact only contains BusyBox!

In the Filesystem images menu, we have enabled the ext2/3/4 root filesystem type and chosen the ext4 variant. As explained above, ext4 is kind of the de-facto standard Linux filesystem for block storage devices such as SD cards.

In the Bootloaders menu, we enabled U-Boot, where a significant number of options need to be tweaked:

  • We download U-Boot from a STMicroelectronics Git repository at https://github.com/STMicroelectronics/u-boot.git and use the Git tag v2018.11-stm32mp-r2.1.
  • This U-Boot comes with a pre-defined configuration called stm32mp15_basic, which we select using Board defconfig.
  • However, it turns out that this pre-defined configuration enables the STM32 watchdog, and since our Linux user-space does not have a watchdog daemon to tick the watchdog regularly, it would reset constantly. Using a small additional snippet of U-Boot configuration, stored in the file board/stmicroelectronics/stm32mp157-dk/uboot-fragment.config, we disable the watchdog. Of course, it should be re-enabled and properly handled in Linux user-space for a final product.
  • In the U-Boot binary format sub-menu, we tell Buildroot that the second stage bootloader image will be called u-boot.img, and this is the one Buildroot should install in output/images
  • We tell Buildroot that our U-Boot configuration will build a first stage bootloader called spl/u-boot-spl.stm32, which allows Buildroot to install it in output/images
  • Finally, we pass a custom DEVICE_TREE=stm32mp157c-dk2 option in the U-Boot environment, which is needed for the U-Boot build process to find the Device Tree used internally by U-Boot.

Finally, in the Host utilities menu, we enable the host genimage package.

This entire configuration is saved in a simple text file called configs/stm32mp157_dk_defconfig, which is the one we loaded initially when running make stm32mp157_dk_defconfig. We suggest you take a moment to look at configs/stm32mp157_dk_defconfig and see the configuration options it defines.

What happens during the Buildroot build?

With all these options in place, here is what Buildroot has done to build our system (we have omitted some intermediate steps or package dependencies for the sake of brievity):

  1. Download and install the pre-built ARM compiler from ARM’s website, and install the C and C++ libraries inside the target root filesystem
  2. Download the Linux kernel source code from STMicroelectronics Github repository, configure it with our configuration file, build it, install zImage and stm32mp157c-dk2.dtb both in output/images and in the target root filesystem in the /boot directory. It also installs the Linux kernel modules inside the target root filesystem
  3. Download the U-Boot source code from STMicroelectronics Github repository, configure it, build it and install u-boot-spl.stm32 and u-boot.img in output/images
  4. Download the Busybox source code from the project official website, configure it, build it and install it inside the target root filesystem.
  5. Copies the contents of the rootfs overlay inside the target root filesystem
  6. Produce the ext4 image of the root filesystem, and install it as output/images/rootfs.ext4
  7. Call the genimage.sh script, whose purpose is to generate the final SD card image, output/images/sdcard.img

Let’s now have a look at the file board/stmicroelectronics/stm32mp157-dk/genimage.cfg, which tells the genimage utility how to create the final SD card image:

image sdcard.img {
        hdimage {
                gpt = "true"
        }

        partition fsbl1 {
                image = "u-boot-spl.stm32"
        }

        partition fsbl2 {
                image = "u-boot-spl.stm32"
        }

        partition uboot {
                image = "u-boot.img"
        }

        partition rootfs {
                image = "rootfs.ext4"
                partition-type = 0x83
                bootable = "yes"
                size = 256M
        }
}

What this file says is:

  • We want to create a file named sdcard.img
  • This file will contain a number of partitions, described by a GPT partition table. This is necessary for the STM32MP157 built-in ROM code to find the first stage bootloader.
  • The first two partitions are named fsbl1 and fsbl2, and contain the raw binary of the first stage bootloader, i.e there is no filesystem in those partitions. it is the STM32MP157 built-in ROM code that is hardcoded to search the first stage bootloader in the first two partitions whose name start with fsbl.
  • The third partition named uboot contains the second stage bootloader, also as a raw binary (no filesystem). Indeed, the first stage bootloader is configured to search the second bootloader from the third partition of the SD card (this is defined in the U-Boot configuration and can be modified if needed)
  • The fourth partition contains the ext4 filesystem image that Buildroot has produced, which is in fact our Linux root filesystem, with BusyBox, the standard C/C++ libraries and the Linux kernel image and Device Tree Blob.

This last partition is marked bootable. This is important because the U-Boot configuration for the STM32MP157 hardware platform by default uses the U-Boot Generic Distro Concept. At boot, U-Boot will search for the partition marked bootable, and then inside the filesystem contained in this partition, look for the file /boot/extlinux/extlinux.conf to know how to boot the system.

This file extlinux.conf is inside our root filesystem overlay at board/stmicroelectronics/stm32mp157-dk/overlay/boot/extlinux/extlinux.conf, so it is installed in our root filesystem as /boot/extlinux/extlinux.conf so that U-Boot finds it. This file simply contains:

label stm32mp15-buildroot
  kernel /boot/zImage
  devicetree /boot/stm32mp157c-dk2.dtb
  append root=/dev/mmcblk0p4 rootwait

Which tells U-Boot that the kernel image to load is /boot/zImage, that the Device Tree Blob to use is /boot/stm32mp157c-dk2.dtb and that the string root=/dev/mmcblk0p4 rootwait must be passed as arguments to the Linux kernel when booting. The root=/dev/mmcblk0p4 is particularly important, because it is the one telling the Linux kernel where the root filesystem is located.

So, if we summarize the boot process of our hardware platform with those new details in mind, it looks like this:

  1. The STM32MP157 built-in ROM code looks for the GPT partitions whose name start with fsbl, and if one is found, loads the contents into the STM32 internal memory and runs it. This is our first stage bootloader.
  2. This first stage bootloader is hard-coded to load the second stage bootloader from the third partition of the SD card. So it initializes the external RAM, loads this second stage bootloader into external RAM and runs it.
  3. The second stage bootloader does some more initialization, and then looks for a partition marked bootable. It finds that the fourth partition is bootable. It loads the /boot/extlinux/extlinux.conf file, thanks to which it learns where the kernel and Device Tree are located. It loads both, and starts the kernel with the arguments also specified in the extlinux.conf file.
  4. The Linux kernel runs, up to the point where it mounts the root filesystem, whose location is indicated by the root=/dev/mmcblk0p4 argument. After mounting the root filesystem, the kernel starts the first user-space process.
  5. The first user-space process that runs is /sbin/init, implemented by BusyBox. It starts a small number of services, and then starts the login prompt.

Conclusion

In this long initial blog post, we have learned what Buildroot is, how to use it to build a basic system for the STM32MP157 platform, how the Buildroot configuration was created, and how the STM32MP157 platform is booting.

Stay tuned for the next blog post, during which we will learn how to plug an additional device to the board: a pressure, temperature and humdity sensor connected over I2C, and how to make it work with Linux.

Linux 5.1 released, Bootlin contributions

LinuxLinux 5.1 was released a a few days ago by Linus Torvalds. As usual, LWN covered the major new features of this release by looking at what got merged during the merge window: part 1 and part 2. KernelNewbies also has a nice summary.

Bootlin contributed 181 commits to this release, making us the 14th contributing company by number of commits. Taking the entire Git history of the kernel, Bootlin has contributed a total of 6256 patches, making us the 15th contributing company by number of commits: a demonstration of our long-term involvement in the upstream Linux kernel community.

For Linux 5.1, our significant contributions have been:

  • In the RTC subsystem
    • Alexandre Belloni contributed a new RTC driver for the RV3028 RTC
    • Alexandre Belloni, as the maintainer of the RTC subsystem, continued to contribute a number of fixes/improvements in various RTC drivers
  • As part of a customer project in which we ported a modern U-Boot and Linux to a custom NXP LPC3250 platform, Alexandre Belloni contributed a fix for the LPC3250 serial port driver, and Grégory Clement moved the LPC3250 Analog-to-Digital converter Device Tree binding out of staging. We have other patches/fixes related to LPC3250 in the pipeline.
  • In the support for Marvell platforms
    • Antoine Ténart contributed numerous improvements to the mvpp2 driver, especially to properly handle the reset state of the different hardware blocks depending on how a particular Ethernet port is configured.
    • Grégory Clement contributed a new cpufreq driver to support CPU frequency scaling on Marvell Armada 8K
    • Maxime Chevallier contributed numerous improvements to the marvell10g Ethernet PHY driver, mainly to support 2.5G and 5G speeds, and to support the 88E2110 PHY. He also enabled 2.5G support in the mvpp2 Ethernet MAC driver.
    • Miquèl Raynal continued his work to bring suspend/resume support to the Armada 37xx platform: he added support for the Armada 37xx COMPHY and Armada 37xx USB UTMI PHY, added suspend/resume in ehci-orion, improved the USB core code to use the generic PHY API, and did a number of related Device Tree changes.
  • In the support for RaspberryPi platforms
    • Boris Brezillon made some fixes in the vc4 display controller driver: support for X/Y reflection was added, negative X/Y positioning was fixed, and support for margins on HDMI displays was added.
  • In the support for Allwinner platforms
    • Maxime Ripard made a number of small improvements to the Allwinner display controller driver
    • Paul Kocialkowski contributed a number of improvements to the support of YUV planes in the Allwinner display controller driver, in relation to our work on the Allwinner VPU support.
    • Paul Kocialkowski contributed some Device Tree changes to enable the Allwinner VPU on Allwinner A10, as well as a few fixes for the Allwinner VPU driver itself.
    • As listed below, Boris Brezillon converted the Allwinner NAND controller driver to the exec_op interface.
  • After extending the generic PHY subsystem in Linux 5.0 with two new hooks phy_configure() and phy_validate(), Maxime Ripard used this extension to add a driver for the Cadence D-PHY (used in combination with Cadence MIPI DSI and CSI transceivers), to convert the Allwinner A31 DSI D-PHY handling to the generic PHY subsystem, and converted the Cadence DSI driver to use the generic PHY API.
  • In the MTD subsystem
    • The NAND controller driver for Allwinner platform was converted to the use the new exec_op interface by Boris Brezillon.
  • In the GPIO subsystem
    • Thomas Petazzoni added support in the core GPIO subsystem to enable pull-up/pull-down resistors available in some GPIO controllers. It was contributed together with an implementation for the PCA953x family of I2C GPIO expanders.

In addition to writing code and submitting patches, a number of Bootlin engineers are also maintainers of various areas in the Linux kernel. As part of their maintainer duties, they review and merge patches from other developers:

  • Maxime Ripard, as the Allwinner platform maintainer, merged 76 patches from other developers
  • Alexandre Belloni, as the RTC subsystem maintainer and Atmel/Microchip platform co-maintainer, merged 53 patches from other developers
  • Miquèl Raynal, as the NAND subsystem maintainer, merged 38 patches from other developers
  • Grégory Clement, as the Marvell platform maintainer, merged 18 patches from other developers

And finally, here is as usual the detailed list of each patch we contributed:

Embedded Linux system development course on STM32MP1 Discovery

Embedded Linux system developmentFor many years, Bootlin has been offering an Embedded Linux system development training course, which has been delivered world-wide to hundreds of engineers by Bootlin trainers. This course is the most appropriate one for engineers getting started with embedded Linux: it goes through all the software layers of an embedded Linux system, from the toolchain to the application, through the bootloader, Linux kernel and basic user-space. With numerous hands-on labs, attendees get practical experience during this training, and learn how to build their embedded Linux system from the ground-up.

This course has been available for a while in two variants:

  • A 5-day variant, which covers all topics, including flash storage and filesystems as well as-real time
  • A 4-day variant, which is identical to the 5-day variant, except that flash storage and filesystem and real-time are not covered

Embedded Linux system developmentToday, we are happy to announce that all the practical labs of our 4-day variant are now done on the recently announced STM32MP157 Discovery board, which uses the STM32MP157 processor from STMicroelectronics. This processor has a number of interesting features for a large number of embedded applications, as we discussed in a previous blog post.

Just like for all our training courses, the training materials for this course are publicly and freely available:

Bootlin trainers are available to deliver this course on-site anywhere in the world. See this page for more details in terms of cost and registration process.

STM32MP1 system-on-chip, Bootlin member of ST Partners program

Earlier this year at Embedded World, STMicroelectronics announced the release of their first MPU, the STM32MP1 system-on-chip. Bootlin has been selected as one of the companies offering engineering and training services to be part of the ST Partners program around this new platform. In this blog post, we will give more details about STM32MP1 and Bootlin’s initial efforts on this platform.

The STM32MP1 platform

For the past several years, STMicroelectronics has developed a range of 32-bit microcontrollers based on the ARM Cortex-M cores. The most high-end ones, based on Cortex-M4 and M7, were powerful enough to run a Linux operating system with external RAM attached, and ST has been very active in adding support for these micro-controllers in the upstream U-Boot and Linux projects. However, the Cortex-M4 and M7 being MMU-less processor cores, Linux could work only with a number of limitations, preventing from using some complex Linux software stacks.

Block diagram of the STM32MP157
Block diagram of the STM32MP157
With the STM32MP1, ST is now offering a full-featured microprocessor, based on the combination of one or two Cortex-A7 cores (650 Mhz), one Cortex-M4 core (209 Mhz) and a wide variety of peripherals. The STM32MP1 is currently available in 3 variants:

  • STM32MP151, featuring one Cortex-A7, one Cortex-M4, and the common set of peripherals
  • STM32MP153, featuring two Cortex-A7, one Cortex-M4, the common set of peripherals plus CAN-FD
  • STM32MP157, featuring two Cortex-A7, one Cortex-M4, the common set of peripherals plus a 3D GPU, a DSI display interface and CAN-FD

The hardware blocks integrated in the STM32MP1 offers a large amount of features and connectivity options:

  • External DDR controller, supporting up to LPDDR2/3 and DDR3
  • QuadSPI memory interface
  • NAND flash controller, with built-in ECC capability
  • 6 I2C controllers
  • 4 UARTs and 4 USARTs
  • 6 SPI controllers
  • 4 SAI audio interfaces
  • HDMI-CEC interface
  • 3 SD/MMC controllers
  • 2 CAN controllers
  • 2 USB host + 1 USB OTG controllers
  • 1 Gigabit Ethernet MAC
  • Camera interface (parallel)
  • 2 ADCs, 2 DACs, 1 digital filter for sigma delta modulators
  • LCD controller supporting up to 1366×768
  • GPU from Vivante (which means open-source support is available!)
  • MIPI DSI
  • Plenty of timers
  • Crypto accelerators, random number generator (only in the C variants of the SoC)
  • Secure boot (only in the C variants of the SoC)

This combination of a wide range of connectivity options, graphics support with GPU support, and a Cortex-M4 for real-time logic, makes the STM32MP1 interesting for a large number of applications.

Software support for the STM32MP1

Bootlin being a consulting company specialized in low-level Linux software for embedded platforms, it is obviously a key aspect we looked at for the STM32MP1 platform.

First of all, a number of hardware blocks used in the STM32MP1 platform were already used on previous micro-controllers from ST and were therefore already supported in upstream projects such as U-Boot and Linux. The fact that these micro-controller products can run upstream versions of U-Boot and Linux is a good indication of ST’s strategy in terms of upstream support.

Then, even before the STM32MP1 product was publicly announced, a significant number of ST engineers had already started contributing to upstream TF-A, U-Boot and Linux the support for various pieces needed for the STM32MP1. Even if the support is not entirely upstream at this point, this strategy of starting the upstreaming effort ahead of the product announcement is very good.

Even though the work towards open-source GPU support has tremendously progressed over the past years, GPUs were notoriously known for being difficult to support in a fully open-source software stack. It is interesting to see that ST has chosen the GPU from Vivante for this STM32MP1, as Vivante is one of the first embedded GPU supported by Mesa, the open-source OpenGL implementation. Vivante GPUs are already used in a number of other SoCs, especially from NXP, and the Vivante open-source support, called etnaviv has therefore already seen some significant usage in production.

Until all the support for the STM32MP1 is fully upstreamed, ST provides publicly available Git repositories for all pieces of the software stack:

In addition to the availability of the code, there is also plenty of documentation available in the Development zone of the STM32 MPU wiki.

Hardware platforms for the STM32MP1

ST provides a low-cost evaluation platform called Discovery, available in two versions:

  • STM32MP157A-DK1, which features the STM32MP157A processor (all features, but without secure boot), LEDs, push buttons, Ethernet, one USB-C connector, 4 USB-A connectors, HDMI, microSD, analog audio, Arduino and RPi compatible connectors. The cost is $69.
  • STM32MP157C-DK2 features the STM32MP157C processor (all features including secure boot), and has the same features as the DK1 variant, with the addition of a DSI panel with touch and a WiFi/Bluetooth chip. The cost is $99.
STM32MP157-DK2 board
STM32MP157-DK2 board

ST also provides some more feature-complete evaluation boards: the STM32MP157A-EV1 and STM32MP157C-EV1, which only differ by the lack or availability of secure boot support. They offer more hardware features than the Discovery platforms, and are obviously available at a higher cost, $399.

In addition to these platforms provided by ST, several manufacturers have already announced a number of boards or system-on-module based on the STM32MP1:

OSD32MP15x system-in-package
OSD32MP15x system-in-package

Bootlin member of ST’s partner program

Bootlin is proud to have been chosen by ST to be part of its partner program when the STM32MP1 platform was announced. As a software partner, Bootlin can offer its training and engineering services to customers using the STM32MP1. We can provide:

  • Engineering for the development of Linux Board Support Packages for STM32MP1 platforms: porting U-Boot, porting Linux, writing Linux device drivers, delivering a fully integrated and optimized Linux system generated with Yocto or Buildroot
  • Training on embedded Linux, Linux kernel development and Yocto usage around the STM32MP1 platform

Bootlin trainings on STM32MP1

As a ST partner, Bootlin will be porting two of its existing training courses to the STM32MP1 platform: this means that all the practical labs in those courses will take place on the STM23MP157 Discovery board. We will soon be announcing:

Of course, as Bootlin has always done, all the training materials will be made freely available, under the same Creative Commons license we already use for existing training materials.

Building a Linux system for STM32MP1

The STM32MP1 being the first micro-processor in this family of SoCs from ST, a number of companies will most likely migrate from a micro-controller environment to a micro-processor one. This means moving from a situation where only a bare-metal application or a simple RTOS is used, to a situation where a feature-rich operating system such as Linux is being used. This migration is not always trivial as it requires gaining a lot of knowledge about U-Boot, the Linux kernel, Linux system integration and development, and more.

In order to help with this, in addition to the training courses described above, we will soon start publishing a series of blog posts that describe step by step how to build a Linux system for the STM32MP157 Discovery Kit, all the way up to reading data from an I2C sensor, and displaying them in a Qt5 based application. Stay tuned on our blog for those articles in the next few weeks!

Buildroot training course updated: Buildroot 2019.02, BeagleBone Black Wireless

Buildroot logoBootlin has been for many years a key contributor to the Buildroot project, a very popular embedded Linux build system. A few years ago, we decided to share our Buildroot expertise by creating a corresponding training course: Embedded Linux development with Buildroot, for which the training materials are freely available, under a Creative Commons license.

We have recently updated this training course up to Buildroot 2019.02, which is the latest “long term support” release of the project. Both the lectures and practical labs have been updated to this Buildroot version.

BeagleBone Black WirelessIn addition, the board used in the course has been changed to the BeagleBone Black Wireless, instead of the BeagleBone Black, which is no longer easily available. The practical labs were updated accordingly, and we now use the USB device interface to provide network connectivity between the development PC and the embedded target.

This 3-day Buildroot training course can be delivered on-site at your location, anywhere in the world. See our cost and registration page for more details.

Feedback from the Netdev 0x13 conference

The Netdev 0x13 conference took place last week in Prague, Czech Republic. As we work on a variety of networking topics as part of our Linux kernel contributions, Bootlin engineers Maxime Chevallier and Antoine Ténart went to meet with the Linux networking community and to see a lot of interesting sessions. It’s the third time we enjoy attending the Netdev conference (after Netdev 2.1 and Netdev 2.2) and as always, it was a blast!

The 3-day conference started with a first day of workshops and tutorials. We enjoyed learning how to be the cool kids thanks to the XDP hands-on tutorial where Jesper Brouer and Toke Høiland-Jørgensen cooked us a number of lessons to progressively get to learn how to write and load XDP programs. This was the first trial-run of the tutorial which is meant to be extended and used as a material to go through the XDP basics. The instructions are all available on Github.

We then had the chance to attend the TC workshop where face to face discussions and presentations of the traffic control hot topics being worked on happened. The session caught our attention as the topic is related to current subjects being worked on at Bootlin.

Being used to work on embedded systems, seeing the problems the Network developers face can sometimes come as a surprise. During the TC workshop, Vlad Buslov presented his recent work on removing TC flower’s the dependency to the global rtnl lock, which is an issue when you have a million classification rules to update quickly.

We also went to the hardware offload workshop. The future of the network offload APIs and support in the Linux kernel was discussed, with various topics ranging from ASIC support to switchev advanced use-cases or offloading XDP. This was very interesting to us as we do work on various networking engines providing many offloading facilities to the kernel.

The next two days were a collection of talks presenting the recent advances in the networking subsystem of the Linux kernel, as well as current issues and real-world examples of recent functionalities being leveraged.

As always XDP was brought-up with a presentation of XDP offloading using virtio-net, recent advances in combining XDP and hardware offloading techniques and a feedback from Cloudflare using XDP in their DDOS mitigation in-house solution.

But we also got to see other topics, such as SO_TIMESTAMPING being used for performance analytics. In this talk Soheil Hassas Yeganeh presented how the kernel timestamping facilities can be used to track individual packets withing the networking stack for performance analysis and debugging. This was nice to see as we worked on enabling hardware timestamping in networking engines and PHYs for our clients.

Another hot topic this year was the QUIC protocol, which was presented in details in the very good QUIC tutorial by Jana Iyengar. Since this protocol is fairly new, it was brought-up in several sessions from a lot of interesting angles.

Although QUIC was not the main subject of Alissa Cooper’s keynote on Open Source, the IETF, and You, she explained how QUIC was an example of a protocol that is designed alongside its implementations, having a tight feedback loop between the protocol specifications and its usage in real-life. Alissa shared Jana’s point on how middle-boxes are a problem when designing and deploying new protocols, and explained that an approach to overcome this “ossification” is to encrypt the protocol header themselves and document the invariant parts of the non-encrypted parts.

A consequence of having a flexible protocol is that it is not meant to be implemented in the kernel. However, Maciej Machnikowski and Joshua Hay explained that it is still possible to offload some of the processing to hardware, which sparked interesting discussions with the audience on how to do so.

Conclusion

The Netdev 0x13 conference was well organized and very pleasant to attend. The content was deeply technical and allowed us to stay up-to-date with the latest developments. We also had interesting discussions and came back with lots of ideas to explore.

Thanks for organizing Netdev, we had an amazing time!

Allwinner VPU campaign one-year anniversary

Crowdfunding Campaign

It has been over a year since we launched a crowdfunding campaign to fund the development of an upstream Linux kernel driver and userspace support for the Allwinner VPU. The funding campaign was a frank success, with over 400 backers contributing a total of over 30 k€ out of the 17,6 k€ set as the initial goal. This enabled us to work on additional stretch goals, namely support for new Allwinner SoCs and H.265 decoding support.

Initial Development

Work on the Allwinner VPU started back in March 2018, being the main topic of my 6-month internship at our office in Toulouse. Bootlin engineer and long-time Allwinner Linux kernel maintainer Maxime Ripard rapidly joined the effort hands-on, to bring up support for H.264 decoding. Aspects covered by our effort include the kernel driver (cedrus), VAAPI userspace library (libva-v4l2-request) as well as testing tools (v4l2-request-test, libva-dump) and various upstream projects such as VLC and GStreamer.

We worked hard to deliver the campaign’s goals and submitted numerous revisions of the base cedrus driver along the way. By July, we announced the delivery of the campaign’s main goals (although some goals were not fully met, as explained in the associated blog post) and accompanied it with a release (tagged release-2018-07 in our git repositories).

By the end of August, we had added support for MPEG-2, H.264 and H.265 for first-generation Allwinner SoCs (and the H3 in addition), including support for accelerated display of decoded frames in the DRM driver. See our detailed blog post presenting the status at that point. Still, our changes had yet to be included in the Linux kernel.

End of the Year Status

We kept working intermittently on VPU support over the following months and manged to get the Cedrus driver accepted in Linux at the same time as the media request API. We also continued to work on submitting new versions of the series adding H.264 and H.265 support to our driver. Last but not least, we worked on adding support for the H5, A64 and A10 platforms, which were missing from the initial delivery. A dedicated blog post presents the status at the end of 2018.

Recent Developments

In 2019, Bootlin has been continuing the effort to maintain the driver and get the remaining patch series integrated in the mainline Linux kernel. We managed to get the remaining patches for DRM support merged and they will be included in Linux 5.1!

Regarding codecs support, there are still discussions happening around the H.264 and H.265 series which are now at their sixth and third revisions respectively. We are hoping that the situation will settle and that these series will be merged (in staging) as soon as possible.

March 2019 Release

With modifications taking place in the (unstable) kernel interface and userspace being updated accordingly, it became quite hard for users to properly pick the kernel and userspace components that work together. Because of that, we decided to make a new release (tagged release-2019-03 in our git repositories). It packs an updated kernel tree (based on the next media tree with our ongoing patch series applied atop) and matching versions of libva-v4l2-request and v4l2-request-test.

External Contributions

We received a few contributions along the way, such as support for the H6 SoC in the cedrus driver (that should make it to Linux 5.2) and a few minor fixes for the driver. We also received and reviewed improvement to our v4l2-request-test testing tool.

More Improvements to Raspberry Pi Display Testing

Raspberry Pi Display Support and IGT

We have been working with Raspberry Pi for quite some time, especially on areas related to the display side. Our work is part of a larger ongoing effort to move away from using the VC4 firmware for display operations and use native Linux drivers instead, which interact with the hardware directly. This transition is a long process, which requires bringing the native drivers to a point where they are efficient and reliable enough to cover most use cases of Raspberry Pi users.

Continuous Integration (CI) plays an important role in that process, since it allows detecting regressions early in the development cycle. This is why we have been tasked with improving testing in IGT GPU Tools, the test suite for the DRM subsystem of the kernel (which handles display). We already presented the work we conducted for testing various pixel formats with IGT on the Raspberry Pi’s VC4 last year. Since then, we have continued the work on IGT and brought it even further.

Improving YUV and Adding Tiled Pixel Formats Support

We continued the work on pixel formats by generalizing support for YUV buffers and reworking the format conversion helpers to support most of the common YUV formats instead of a reduced number of them. This lead to numerous commits that were merged in IGT:

In the meantime, we have also added support for testing specific tiling modes for display buffers. Tiling modes indicate that the pixel data is laid out in a different fashion than the usual line-after-line linear raster order. It provides more efficient data access to the hardware and yields better performance. They are used by the GPU (T tiling) or the VPU (SAND tiling). This required introducing a few changes to IGT as well as adding helpers for converting to the tiling modes, which was done in the following commits:

DRM Planes Support

The display engine hardware used on the Raspberry Pi allows displaying multiple framebuffers on-screen, in addition to the primary one (where the user interface lives). This feature is especially useful to display video streams directly, without having to perform the composition step with the CPU or GPU. The display engine offers features such as colorspace conversion (for converting YUV to RGB) and scaling, which are usually quite intensive tasks. In the Linux kernel’s DRM subsystem, this ability of the display engine hardware is exposed through DRM planes.

Displaying multiple DRM planes

We worked on adding support for testing DRM planes with the Chamelium board, with a fuzzing test that selects randomized attributes for the planes. Our work lead to the introduction of a new test in IGT:

Dealing with Imperfect Outputs

With the Chamelium, there are two major ways of finding out whether the captured display is correct or not:

  • Comparing the captured frame’s CRC with a CRC calculated from the reference frame;
  • Comparing the pixels in the captured and reference frames.

While the first method is the fastest one (because the captured frame’s CRC is calculated by the Chamelium board directly), it can only work if the framebuffer and the reference are guaranteed to be pixel-perfect. Since HDMI is a digital interface, this is generally the case. But as soon as scaling or colorspace conversion is involved, the algorithms used by the hardware do not result in the exact same pixels as performing the operation on the reference with the CPU.

Because of this issue, we had to come up with a specific checking method that excludes areas where there are such differences. Since our display pattern resembles a colorful checkerboard with solid-filled areas, most of the differences are only noticeable at the edges of each color block. As a result, we introduced a checking method that excludes the checkerboard edges from the comparison.

Detecting the edges (in blue) of a multi-plane pattern

This method turned out to provide good results and very few incorrect results after some tweaking. It was contributed to IGT with commit:

Underrun Detection

We also worked on implementing display pipeline underrun detection in the kernel’s VC4 DRM driver. Underruns occur when too much pixel data is provided (e.g. because of too many DRM planes enabled) and the hardware can’t keep up. In addition, a bandwidth filter was also added to reject configurations that would likely lead to an underrun. This lead to a few commits that were already merged upstream:

We prepared tests in IGT to ensure that the underruns are correctly reported, that the bandwidth protection does its job and that both are consistent. This test was submitted for review with patch:

Linux 5.0 released, Bootlin contributions

Linux 5.0 was released two weeks ago by Linus Torvalds, and as it is now always the case, Bootlin has contributed a number of patches to this release. For an overview of the new features and improvements brought by Linux 5.0, we as usual recommend to read the LWN articles: merge window summary part 1, merge window summary part 2. The KernelNewbies.org page about this kernel release is also nicely documented.

In terms of contribution to Linux 5.0, according to the LWN statistics, Bootlin is the 12th contributing company by number of commits (261 commits), and 8th contributing company by number of changed lines. Bootlin engineer Maxime Ripard is 11th contributing developer by number of commits, and former Bootlin engineer Boris Brezillon is 12th contributing developer by number of commits, and 8th by number of changed lines. In this release, we are also happy to see numerous contributions from Paul Kocialkoswki who joined Bootlin in November 2018 after his internship working on the Linux kernel support for the Allwinner VPU.

Here are the main highlights of our contributions to Linux 5.0:

  • After 1.5 years of work, the I3C subsystem was finally merged and visible in drivers/i3c in your favorite kernel tree! We are proud to have pioneered the Linux kernel support for this new MIPI standard, which aims at providing an alternate solution to I2C and SPI, with interesting new features (higher speed, device discovery and enumeration, in-band interrupts, and more). See also our initial blog post about I3C, and our blog post about I3C being upstream.
  • In the RTC subsystem, Bootlin engineer and RTC kernel maintainer Alexandre Belloni reworked the way nvmem devices are handled, allowing for multiple nvmem devices to be registered for a single RTC as some have both battery-backed RAM and an on-chip EEPROM. devm_rtc_device_register() has been reimplemented to use the new registration path and is now deprecated. Its counterpart, devm_rtc_device_unregister() has been removed.
  • In the MTD subsystem
    • Boris Brezillon contributed a number of patches to the support for raw NAND mainly related to refactoring the subsystem. For example, some of the patches make the ->select_chip() of nand_chip a legacy hook, and removes its implementation from a number of drivers. All those patches do not bring any new feature per-se, but are part of a larger effort to clean up and modernize the MTD subsystem.
    • Boris Brezillon also contributed to the SPI NOR support a mechanism to fixup the information provided in the BFPT table of SPI NOR flashes. This is used to ensure that some Macronix SPI NOR flashes are properly recognized as supporting 4-byte opcodes.
  • Maxime Ripard contributed a number of improvements to the OV5640 camera sensor driver, especially to remove the hardcoded initialization sequence by a much more flexible initialization code, which allowed to support 60fps and more resolutions.
  • Maxime Ripard extended the PHY subsystem with two new functions, phy_configure() and phy_validate(), which allow to pass configuration details to PHY drivers. This was then used by Maxime to implement MIPI D-PHY drivers, which need a significant number of configuration parameters. See this commit and this commit for details. MIPI D-PHY are typically used in video display or capture HW pipelines.
  • As part of our work on RaspberryPi display support, Boris Brezillon contributed a number of fixs to the VC4 display controller driver.
  • For the support of Microchip MPU (Atmel) platforms, Alexandre Belloni migrated the AT91SAM9260, AT91SAM9261, AT91SAM9263, AT91SAM9RL, AT91SAM9x5, SAMA5D2 and SAMA5D4 platforms to the new clock Device Tree binding that he introduced in Linux 4.20.
  • For the support of Microchip UNG (formerly Microsemi) platforms, Alexandre Belloni added support for the Jaguar2 platform to the pinctrl driver already used for the Ocelot platform.
  • For the support of Allwinnner platforms:
    • Maxime Ripard did a huge amount of Device Tree cleanups and improvements, fixing DTC warnings, but generally making sure those Device Tree files are consistent.
    • Paul Kocialkowski implemented support for YUV planes in the Allwinner display controller driver. This allows to display a video decoded by the VPU directly into a display controller plane, and let the hardware compose it with other display planes, without CPU intervention.
    • Paul Kocialkowski enabled the VPU (for hardware-accelerated video decoding) on the Allwinner H5 and A64. This work was part of our crowdfunding campaign around the Allwinner VPU support.
  • For the support of Marvell platforms
    • Miquèl Raynal added support for suspend/resume to the SATA support on Armada 3720 (the SoC used for the popular EspressoBin platform), as part of a larger effort of bringing full suspend/resume support on Armada 3720
    • Miquèl Raynal implemented support for the thermal overheat interrupt on Armada 7K/8K.

Here is the detailed list of commits we contributed to Linux 5.0:

Raspberry Pi: update breaks Raspbian Stretch

Raspberry Pi logoToday, the three Raspberry Pis that we have on our network went down. They were all running Raspbian (Debian for Raspberry Pi) Stretch.

While this issue can be solved, it is serious enough to require to remove the micro-SD card and manually fix the the root filesystem. Therefore, it seems you cannot fix this issue unless you have physical access to your system.

Here are details to attract attention to this issue…

As I started telling you, our systems were down, well almost. Some services were still running, as they were still responding to ping through our VPN. However, SSH access was no longer available:

$ ssh scan
ssh_exchange_identification: Connection closed by remote host

After connecting a serial cable to one of the Pis, and adding init=/bin/sh to the /boot/cmdline.txt file. I found that I couldn’t seem to execute at least some executables. Everything I tried to execute was causing a segmentation fault.

It was time to remove the micro-SD card and look at system logs. Inspecting /var/log/apt/history.log revealed that the raspi-copies-and-fills package was updated yesterday (March. 11, 2019). This allowed me to make a search for issue reports with this package name. Indeed, before having such a lead, I couldn’t find what I was looking for, as there are too many discussions about the use of the Raspberry Pi! So, here’s what I quickly found following this lead:

raspi-copies-and-fills package gone AWOL? (Raspberry Pi forums)
Ras3 crashes after update (Raspberry Pi forums)

These posts have all details. All you need to do is take away the micro-SD card, repair the second partition with e2fsck -f /dev/mmcblk0p2 and remove the etc/ld.so.preload file inside this partition.

Note, that at the time of this writing, this issue has already been fixed, so it is safe to upgrade your Pi if it is still up and running, or right after repairing your Raspbian root filesystem.

This incident is very unfortunate, as you need to physically access your board to recover from it. I hope you don’t run updates as frequently as we do (or right after the time when the update was issued), and that your Pis are not impacted, otherwise possibly forcing you to travel or to crawl into difficult to access places to reach your boards.

However, I don’t want blame the community volunteers running Raspbian. They have made a terrific job maintaining this distro which had been flawlessly running for more many years on our systems. This seems as good as what we get from commercial distributions.

I hope that not too many services ran by Raspberry Pis will be disrupted because of this issue. However, that may be yet another way to prove how popular such devices are.