As we mentioned in our last blog post about OP-TEE 3.16, Bootlin planned to and contributed some interesting features in the recently released OP-TEE 3.17 ! Here is a short presentation of our contributions to this release:
Summary
During this release cycle, Bootlin contributed the following features:
Watchdog support
Generic watchdog API
OP-TEE Watchdog service compatible with arm,smc-wdt Linux driver
As part of our work on Microchip SAMA5D2 support in OP-TEE, we wanted to have support for the SAMA5D2 watchdog. Doing so without exposing the watchdog to Linux would have been useless and thus, we implemented and contributed a new generic watchdog API to OP-TEE. This interface allows registering a watchdog against the system and exposing it to Linux through a specific SMC handler that interfaces with the Linux arm,smc-wdt compatible driver (see drivers/watchdog/arm_smc_wdt.c in the Linux kernel code). Our generic watchdog API is obviously used by the new watchdog driver for Microchip SAMA5D2, but was also quickly leveraged by ST who contributed a new watchdog driver for stm32mp1 based on this new watchdog API.
RTC
On Microchip SAMA5D2, the RTC is part of the system controller which needs to be secured since it contains critical features. Once in the secure world, the RTC is not available to the normal world. In order to expose this RTC device to the normal world (and particularly for Linux RTC subsystem), a new Pseudo Trusted Application (PTA) was added. This PTA communicates with a Linux OP-TEE compatible RTC driver and allows to get/set the date and time. This driver is generic and will allow any vendor which adds RTC support to OP-TEE to expose it transparently to Linux.
Contribution details
A total of 29 commits were contributed for OP-TEE 3.17:
Do not hesitate to contact us if you need help and support to integrate or deploy OP-TEE on your platform, either Microchip platforms, but also other ARM32 or ARM64 platforms.
Most of the BeagleBone boards from BeagleBoard.org share the same form factor, have the same headers and therefore can accept the same extension boards, also known as capes in the BeagleBoard world.
Of course, a careful PCB design was necessary to make this possible.
This must have been relatively easy with the early models (BeagleBone Black, Black Wireless, Green, Green Wireless, Black Industrial and Enhanced) which are based on the same Sitara AM3358 System on Chip (SoC) from Texas Instruments. However, the more recent creation of the BeagleBone AI board and keeping compatibility with existing capes must have been a little more complicated, as this board is based on a completely different SoC from Texas Instruments, the Sitara AM5729.
Once the PCB design challenge was completed, the BeagleBoard.org crew set itself another challenge: implement software that supports each BeagleBone cape in the same way, whatever the board, in particular:
To have unique identifiers for devices in Linux, so that there is a stable name for Linux devices, even if at the hardware level they are connected differently, depending on whether the base board has a Sitara AM3358 and Sitara AM5729 SoC.
To have DT overlays for capes that are applicable to all base boards, even if peripherals are connected to different buses of the SoCs.
This article will explore the software solutions implemented by BeagleBoard.org. Their ideas can of course be reused by other projects with similar needs.
The need for a cape standard
A good summary can be found on Deepak Khatri’s Google Summer of Code 2020 page:
The idea of this project was to make the same user space examples work with both BeagleBone Black and BeagleBone AI, using the same references to drivers for peripherals assigned to the same pins between BeagleBone Black and BeagleBone AI. Also, Same DT overlays should work (whenever possible) for both BBB and BBAI, with updated U-Boot cape manager DT overlays will be automatically loaded during boot.
Software setup
The below instructions are for people owning the BeagleBone AI board and any other BeagleBone board, and interested in exploring the devices on their boards by themselves.
Uncompress each image, insert a micro-SD card in the card read in your PC, and then flash the corresponding card. Here are example commands, assuming that the micro-SD card is represented by the /dev/mmcblk0 device:
Connect the serial line of each board to your computer and then boot each board with it:
For BeagleBone AI: its sufficient to have the micro-SD card inserted.
On other BeagleBone boards, you may need to hold a button when you power up the board, to make it boot from the micro-SD card instead of from the internal eMMC. On the BeagleBone Black boards, for examples, that’s the USER button next to the USB host port. Note that you won’t need to do this again when you reset the board. The board will continue to boot from the external micro-SD card until it’s powered off.
You can connect with the default user, or connect as user root with password root.
Then, connect each board to the Internet, and get the latest package updates:
sudo apt update
sudo apt dist-upgrade
It’s then time to upgrade the kernel to the latest version supported by BeagleBoard. To do so, you’ll have to manually update the /opt/scripts/tools/update_kernel.sh file. In this file, go to the # parse commandline options section and add the below lines:
--lts-5_10-kernel|--lts-5_10)
kernel="LTS510"
;;
You can can then upgrade to the latest 5.10 kernel:
Note that on the BeagleBone Black, I2C1 and I2C2 are available at two different locations.
So, for both types of boards, we have at least I2C buses on P9_17/18, P9_19/20 and P9_24/26. However, that’s complicated because these pins don’t correspond to the same I2C buses. Therefore, users have to know that P9_19/20 correspond to I2C2 on BeagleBone Black and to I2C4 on BeagleBone AI.
The devices in /dev/ reflect such differences.
Here’s what we have on the BeagleBone AI:
root@beaglebone:~# ls -la /dev/i2c-*
crw------- 1 root root 89, 0 Mar 23 15:00 /dev/i2c-0
crw------- 1 root root 89, 3 Mar 23 15:00 /dev/i2c-3
Note that here with the AM5729 SoC, the first I2C bus is I2C1. Hence, /dev/i2c-0 corresponds to I2C1 (which is another I2C bus available on the SoC but not available through the cape headers) and /dev/i2c-3 corresponds to I2C4. Also note that I2C5 is not exposed in the default configuration that we have here, most probably because the corresponding header pins are used for other purposes.
And now let’s look at what we have on the BeagleBone Black:
root@beaglebone:~# ls -la /dev/i2c-*
crw------- 1 root root 89, 0 Mar 23 16:16 /dev/i2c-0
crw------- 1 root root 89, 1 Mar 23 16:17 /dev/i2c-1
crw------- 1 root root 89, 2 Mar 23 16:17 /dev/i2c-2
Here with the AM3358 SoC, /dev/i2c-0 corresponds to I2C0, /dev/ic2-1 to I2C1 and /dev/ic2-2 to I2C2.
So, on a running system, how to know which I2C bus device corresponds to the P9_19/20 header pins?
You can see that both devices, though they correspond to different devices, share the same symlink property, which is used to create a symbolic link in /dev/bone/i2c/ to the actual bus device file.
Let’s see such symbolic links on the BeagleBone AI:
root@beaglebone:~# ls -la /dev/bone/i2c/
total 0
drwxr-xr-x 2 root root 80 Jan 1 2000 .
drwxr-xr-x 4 root root 80 Jan 1 2000 ..
lrwxrwxrwx 1 root root 11 Mar 23 15:00 0 -> ../../i2c-0
lrwxrwxrwx 1 root root 11 Mar 23 15:00 2 -> ../../i2c-3
And on the BeagleBone Black:
root@beaglebone:~# ls -la /dev/bone/i2c/
total 0
drwxr-xr-x 2 root root 100 Mar 23 16:16 .
drwxr-xr-x 5 root root 100 Mar 23 16:16 ..
lrwxrwxrwx 1 root root 11 Mar 23 16:16 0 -> ../../i2c-0
lrwxrwxrwx 1 root root 11 Mar 23 16:17 1 -> ../../i2c-1
lrwxrwxrwx 1 root root 11 Mar 23 16:17 2 -> ../../i2c-2
You can see that at least /dev/bone/i2c/0 and /dev/bone/i2c/2 are shared between both types of boards. Userspace code examples can then support different boards by referring to such device file links, for example by using the I2C tools commands.
The symbolic links are created from the Device Tree sources not by the Linux kernel, but by the udev device manager, thanks to the following rule found in /etc/udev/rules.d/10-of-symlink.rules in the BeagleBoard Debian distribution:
# allow declaring a symlink for a device in DT
ATTR{device/of_node/symlink}!="", \
ENV{OF_SYMLINK}="%s{device/of_node/symlink}"
ENV{OF_SYMLINK}!="", ENV{DEVNAME}!="", \
SYMLINK+="%E{OF_SYMLINK}", \
TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/dev/%E{OF_SYMLINK}"
Accessing other devices
Other devices are available in the same way through symbolic links in /dev/bone/, for example UART (serial port) devices.
Let’s check on the BeagleBone AI (run sudo apt install tree first):
Another challenge is with userspace software examples directly refer to header pins by their names. Here is a BoneScript push button demo, for example:
var b = require('bonescript');
b.pinMode('P8_19', b.INPUT);
b.pinMode('P8_13', b.OUTPUT);
setInterval(check,100);
function check(){
b.digitalRead('P8_19', checkButton);
}
function checkButton(x) {
if(x.value == 1){
b.digitalWrite('P8_13', b.HIGH);
}
else{
b.digitalWrite('P8_13', b.LOW);
}
}
For AM3358 BeagleBone boards, the am335x-bone-common-univ.dtsi file already associates the P8_19 name to a specific GPIO:
However, this driver is specific to the BeagleBoard.org kernel, and the Device Tree for Beagle Bone AI doesn’t use it yet, so this aspect is still work in progress. The main goal remains though: define generic names for header pins, which map to specific GPIOs on different boards.
The goal as stated in the beginning is to use the same Device Tree overlays on both types of SoCs. While as of today it doesn’t seem possible to generate compiled Device Tree Overlays (DTBO) which would support both SoCs at the same time, the BeagleBoard.org engineers have come up with a solution to achieve this at source level. This means that, for each cape to support, the Device Tree Overlay binaries for the supported SoCs can be produced from a unique source file.
While this hasn’t been deployed yet in the 5.10 BeagleBoard kernel, such source code is already available in Deepak Khatri’s own tree.
/*
* Copyright (C) 2020 Deepak Khatri
*
* Virtual cape for /dev/bone/can/1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/dts-v1/;
/plugin/;
/*
* Helper to show loaded overlays under: /proc/device-tree/chosen/overlays/
*/
&{/chosen} {
overlays {
BONE-CAN1 = __TIMESTAMP__;
};
};
/*
* Update the default pinmux of the pins.
* See these files for the phandles (&P9_* & &P8_*)
* https://github.com/lorforlinux/BeagleBoard-DeviceTrees/blob/compatibility/src/arm/am335x-bone-common-univ.dtsi
* https://github.com/lorforlinux/BeagleBoard-DeviceTrees/blob/compatibility/src/arm/am572x-bone-common-univ.dtsi
*/
&ocp {
P9_24_pinmux { pinctrl-0 = <&P9_24_can_pin>;}; /* can rx */
P9_26_pinmux { pinctrl-0 = <&P9_26_can_pin>;}; /* can tx */
};
/*
* See these files for the phandles (&bone_*) and other bone bus nodes
* https://github.com/lorforlinux/BeagleBoard-DeviceTrees/blob/compatibility/src/arm/bbai-bone-buses.dtsi
* https://github.com/lorforlinux/BeagleBoard-DeviceTrees/blob/compatibility/src/arm/bbb-bone-buses.dtsi
*/
&bone_can_1 {
status = "okay";
};
The &ocp code applies the pin muxing definitions for CAN on P9_24 (&P9_24_can_pin) and P9_26 (&P9_26_can_pin), which of course are different on AM3358 and AM5729.
By adding a symlink property to the Device Tree sources, BeagleBoard.org has made it possible to make userspace code, in particular its code examples, support all the BeagleBone boards at the same time, even though the devices they drive have are numbered differently on different SoCs.
Such a technique may be reused by other projects interested in running the same software on boards based on different SoCs.
As far as GPIOs are concerned, the drivers/gpio/gpio-of-helper.c driver is specific to the BeagleBoard.org kernel and is unlikely to be accepted in the mainline kernel in its current state. However, there are other solutions, supported by the mainline kernel, to associate names to GPIOs and then to look up such GPIOs by name through libgpiod.
Last but not least, it’s possible to use the same Device Tree Overlay source code to support an extension board on similar boards, just by using common definitions having different values on each different platform. Any project can reuse this idea, which just uses standard Device Tree syntax.
Bootlin thanks BeagleBoard.org for funding the creation of this blog post. Note that another post is coming in the next weeks, about the extension board manager we added to U-Boot thanks to funding from BeagleBoard.org.
Linux 5.17 has been released last Sunday. As usual, the best coverage of what is part of this release comes from LWN (part 1 and part 2), as well as KernelNewbies (unresponsive at the time of this writing) or CNX Software (for an ARM/RISC-V/MIPS focused description).
Bootlin contributed just 34 patches to this release, which isn’t a lot by the number of patches, but in fact includes a number of important new features. Also, we have many more contributions being discussed on the mailing lists or in preparation. For this 5.17 release here are the highlights of our contributions:
Alexandre Belloni, as the maintainer of the RTC subsystem, contributed one improvement to an RTC driver
Clément Léger improved the Microchip Ocelot Ethernet switch driver performance by implementing FDMA support. This allows network packets that are going from the switch to the CPU, or from the CPU to the switch to be received/sent in a much more efficient fashion than before. The Microchip Ocelot Ethernet switch driver was developed and upstreamed several years ago by Bootlin, see our previous blog post.
Clément Léger also contributed smaller fixes: a bug fix in the core software node code, and one PHY driver fix.
Hervé Codina implemented support for GPIO interrupts on the old ST Spear320 platform.
Miquèl Raynal contributed a brand new NAND controller driver, for the NAND controller found in the Renesas RZ/N1 SoC. We expect to contribute to many more aspects of the Renesas RZ/N1 Linux kernel support in the next few months.
Miquèl Raynal contributed a few Device Tree changes enabling the ADC on the Texas Instruments AM473x platform, after contributing the driver changes a few releases ago.
Miquèl Raynal started contributing some improvements to the 802.15.4 Linux kernel stack, and we also have many more changes in the pipe for this Linux kernel subsystem.
Thomas Perrot added support for the Sierra EM919X modem to the existing MHI PCI driver.
In the past months, the Linux kernel driver for the Ethernet MAC found in a number of Marvell SoCs, mvneta, has seen quite a few improvements. Lorenzo Bianconi brought support for XDP operations on non-linear buffers, a follow-up work on the already-great XDP support that offers very nice performances on that controller. Russell King contributed an improved, more generic and easier to maintain phylink support, to deal with the variety of embedded use-cases.
At that point, it’s getting difficult to squeeze more performances out of this controller. However, we still have some tricks we can use to improve some use-cases so in the past months, we’ve worked on implementing QoS features on mvneta, through the use of mqprio.
Multi-queue support
A simple Ethernet NIC (Network Interface Controller) could be described as a controller that handles some protocol-level aspect of the Ethernet standard, where the incoming and outgoing packets would be enqueued in a dedicated ring-buffer that serves as an interface between the controller and the kernel.
The buffer containing packets that needs to be sent is called the Transmit Queue, often written as txq. It’s fed by the kernel, where the NIC driver converts some struct sk_buff objects called skb, that represent packets trough their journey in the kernel, into buffers that are enqueued in the txq.
On the ingress side, the Receive Queue, written rxq, is fed by the MAC, and dequeued by the NIC driver, who creates skb containing the payload and attached metadata.
In the end, every incoming or outgoing packet is enqueued and dequeued in a typical first-in first-out fashion. When the queue is full, packets are dropped, everything is neat, simple and deterministic.
However, typical use-cases are never simple. Most modern NICs have several queues in TX and RX. On the receive side, it’s useful to have multiple queues for performance reasons. When receiving packets, we can spread the traffic across multiple queues (with RSS for example), and have one CPU core dedicated to each queue. More complex use-cases can be expressed, such as flow steering, that you can learn about in the kernel documentation.
On the transmit side, it’s a bit less obvious why we want to have multiple queues. If the CPU is the bottleneck in terms of performances, having multiple TX queues won’t help much. Still, there are ways to benefit from having multiple TX queues on a multi-cpu system with XPS.
However, when the line-rate is the bottleneck, having multiple queues gets useful. By sorting the outgoing traffic by priority and assign each priority to a TX queue, the NIC can then pick the next packet to send from the highest priority queue until it’s empty, and then move on to the next priority. That way, we implement what’s called QoS (Quality of Service), where we care about high-priority traffic making it through the controller.
QoS itself is useful for various reasons. Besides the obvious prioritization of high-value streams for not-so-neutral networking, we can also imagine tagging management traffic as high-priority, to guarantee the ability to remotely access a machine under heavy traffic.
Other applications can be in the realm of Time Sensitive Networking, where it’s important that time-sensitive traffic gets sent right-away, using the high-priority queues as shortcuts to bypass the low-priority over-crowded queues.
NICs can use more advanced algorithms to pick the queue to de-queue the packet from, in a process called arbitration, to give low-priority traffic a chance to get sent even when high-priority traffic takes most of the bandwidth.
Typical algorithms range from strict priority-based FIFO to more flexible Weighted Round-Robin arbitration, to allow at least a few low-priority packets to leave the NIC.
In the case of mvneta, we’re limited in terms of what we can do in the receive path. Most of the work we’ve done focused on the transmit side.
Traffic Priorisation and Arbitration
Multi-queue support on the TX path is a three-fold process.
First, we have to know which packets are high-priority and which aren’t, by assigning a value to the skb->priority field.
There are several ways of doing so, using iptables, nftables, tc, socket parameters through SO_PRIORITY, or switching parameters. This is outside of the scope of this article, we’ll assume that incoming packets are already prioritized through one of the above mechanisms.
Once the packet comes into the network stack as a skb, we need to assign it to a TX queue. That’s where tc-mqprio comes in play.
In that second step, we build a mapping between priorities and queues. This mapping is done through the use of an intermediate mapping, the Traffic Classes. A Traffic Class is a mapping between N priorities and M transmit queues. We therefore have 2 levels of mappings to configure :
The priority to Traffic Class mapping (N to 1 mapping)
The Traffic Class to TX queue mapping (1 to M mapping)
All of this is done in one single tc command. We’re not going to dive too much into the tc tool itself, but we’ll still see a bit how tc-mqprio works.
Queuing Disciplines (QDiscs) are algorithms you use to select how and when you enqueue and dequeue traffic on a NIC. It benefits from great software support, but can also be offloaded to hardware, as we’ll see.
So the first part of the command is about attaching the mqprio QDisc to the network interface :
tc qdisc add dev eth0 parent root handle 100 mqprio
After that, we configure the traffic classes. Here, we create 8 traffic classes :
num_tc 8
And then we map each class to a priority. In this list, the n-th element corresponds to the class you want to assign to priority n. Here, we map the 8 first priorities to a dedicated class. Priorities that aren’t assigned a class are mapped to the class 0.
map 0 1 2 3 4 5 6 7
Finally, we map each class to a queue. Classes can only be assigned a contiguous set of queues, so the only parameters needed for the mapping are the number of queues assigned to the class (the number before the @), and the offset in the queue list (after the @). We specify one mapping per class, the m-th element in the list being the mapping for class number m. In the following example, we simply assign one queue per traffic class :
queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7
Under the hood, tc-mqprio will actually assign one QDisc per queue and map the Traffic Classes to these QDiscs, so that we can still hook other tc configurations on a per-queue basis.
Finally, we enable hardware offloading of the prioritization :
hw 1
The last part of the work consists in configuring the hardware itself to correctly prioritize each queue. That’s done by the NIC driver, which gets the configuration from the tc hooks.
If we take a look at the Hardware, we see that the queues are exposed to the kernel, which will enqueue packets into them. Each queue then has a Bandwidth Limiter, followed by the arbitration layer. Finally, we have one last global Rate limiter, and the path then continues to the egress blocks of the controller.
The arbiter configuration is easy, it’s just a matter of enabling the strict priority arbitration in a few registers.
Let’s summarize what the stack looks like :
Traffic shaping
Being able to prioritize outgoing traffic is good, but we can step-it up by allowing to limit the rate on each queue. That way, we can neatly organize and control how we want to use our bandwidth, not on a per-packet level but really on a bits/s basis.
Controlling the rate of individual flows or queues is called Traffic Shaping. When configuring a shaper, not only do we focus on the desired max rate, but also how we deal with traffic bursts. We can smooth them by tightly controlling how and when we send packets, or we can allow some burstiness by being more lenient on how often we enforce the rate limitation.
In the mvneta hardware, we have 2 levels of shaping : one level of per-queue shapers, and one per-port shaper. They can all be controlled semi-independently, some parameters being shared between all shapers.
With mqprio, the shapers are configured on a per-Traffic-Class basis. Since the hardware only allows per-queue shaping, we enforce in the driver that one traffic class is assigned to only one queue.
A final configuration with mqprio looks like this :
Most shapers use a variant of the Token Bucket Filter algorithm. The principle is the following :
Each queue has a Token Bucket, with a limited capacity. When a packet needs to be sent, one token per bit in the packet gets taken from the bucket. If the bucket is empty, transmission stops. The bucket then gets refilled at a configurable rate, with a configurable amount of tokens.
Configuring the TBF for each queue boils down to setting a few parameters :
– The Bucket Size, sometimes called burst, buffer or maxburst.
It should be big enough to accommodate for the shaping rate required, but not too big. If the bucket is too big and you have a very slow traffic going out, the bucket is going to fill up to its full size. When you suddenly have a lot of traffic to send, you’ll first have a huge burst, the time for the bucket to empty, before the traffic starts to actually get limited. Unlike the tc-tbf interface, tc-mqprio doesn’t allow to change the burst size, so it’s up to the driver to set it.
– The Refill Rate, sometimes called tick, defining how often you refill the bucket.
– The Refill Value, defining how many tokens you put back into the bucket at each refill.
These two, combined together, define the actual rate limitation. The approach taken to select the value is to select a fixed value for one of the parameters, and vary the other one to select the desired rate. In the case of mvneta, we chose to use a fixed refill rate, and change the refill value. This means that we have a limited resolution in the rates we can express. In our case, we have a 10kbps resolution, allowing us to cover any rate limitation between 10kbps and 5Gbps, with 10k increments.
– One final parameter is the minburst or MTU parameter, and controls the minimum amount of tokens required to allow packet transmission.
Since transmission stops when the bucket is empty, we can end-up with an empty bucket in the middle of a packet being transmitted.The link-partner may not be too happy about that, so it’s common to set the Maximum Transmission Unit as the minimum amount of tokens required to trigger transmission.
That way, we are sure that when we start sending a packet, we’ll always have enough tokens in the bucket to send the full packet. We can play a bit with this parameter if we want to buffer small packets and send them in a short burst when we have enough. In our case, we simply configured it as the MTU, which is good enough for most cases.
In the end, the gains are not necessarily measurable in terms of raw performances, but thanks to mqprio and traffic shaping, we can now have better control on the traffic that comes out of our interface.
There are tons of other use-cases, for example limiting per-vlan speeds, or in contrary making sure that traffic on a specific vlan has the highest priority, and all of that mostly offloaded to the hardware itself !
The entire team at Bootlin is extremely happy to welcome Luca Ceresoli, who started working with us on March 1, 2022. Based in Italy, Luca is the first employee of Bootlin based outside of France, and we plan to continue to expand our hiring in a similar way in the future.
Luca brings a vast amount of embedded and embedded Linux expertise to the Bootlin team. Luca has been working on embedded products since 2002, and embedded Linux products since 2008. He has helped design, develop and ship products based on a large number of embedded processors, developing complete BSPs, developing Linux kernel drivers, integrating complete systems using Buildroot or Yocto. Luca has also contributed to the Linux kernel, Buildroot, and several open-source projects, and has spoken several times at FOSDEM, the Embedded Linux Conference, and other events.
Luca’s arrival at Bootlin not only means that we have more capacity to help our customers with their embedded Linux projects, but also that we have more capacity to deliver training courses, and a new ability to deliver some of our training courses in Italian.
Last year, Bootlin started contributing to the OP-TEE project, which is an open source Trusted Execution Environment (TEE) implemented using the Arm TrustZone technology. We published a blog post about our contribution of a generic clock framework to OP-TEE, and also presented a talk OP-TEE: When Linux Loses Control (slides, video).
As part of this work, Bootlin engineer Clément Léger contributed to the OP-TEE project, and many of his contributions have already been merged, and released as part of the 3.15 and 3.16 OP-TEE releases. In this blog post, we present some details of our contributions to OP-TEE so far, and our next steps.
Summary
Since then, we contributed a number of features and improvements to OP-TEE. First, a number of generic, HW-agnostic contributions:
We contributed 48 commits to OP-TEE 3.16.0. This level of contribution makes Bootlin engineer Clément Léger the second most active contributor by number of commits for this OP-TEE release.
We will continue our effort on sam5d2 support on OP-TEE and as part of this, there will be contributions on several generic subsystems as well as SAMA5D2 support:
Watchdog support
Generic watchdog API
OP-TEE Watchdog service compatible with arm,smc-wdt Linux driver
Sama5d2 watchdog driver
RTC support
Generic RTC API
OP-TEE RTC PTA to expose RTC to Linux
sama5d2 RTC driver
Linux driver for OP-TEE RTC
SAMA5D2 suspend support
Support forULP0, ULP1, ULP0 Fast and backup modes
PSCI support
SAMA5D2 interrupt controller support
Do not hesitate to contact us if you need help and support to integrate or deploy OP-TEE on your platform, either Microchip platforms, but also other ARM32 or ARM64 platforms.
The Device Tree language is a way to describe hardware that is present in a system and cannot be automatically detected. That’s the case of devices directly implemented on a System on a Chip, such as serial ports, Ethernet or Nand flash controllers. That’s also the case of devices connected to a number of buses, such as I2C and SPI, that do not provide mechanisms for dynamic enumeration and identification of devices.
For a given CPU architecture (ARM, PowerPC, etc), such a description allows to have a unique kernel supporting many different systems with distinct Systems on a Chip. The compiled Device Tree (DTB: Device Tree Binary), passed to the kernel by the bootloader at boot time, lets the kernel know which SoC and devices to initialize. Therefore, when you create a new board, and want to use a standard GNU/Linux distribution on it, all you have to do is create a new Device Tree describing your new hardware, compile it, and boot the distribution’s kernel with it. You don’t need to recompile that kernel, at least when it supports your SoC and the devices on your board.
Kernel developers and board maintainers are not the only ones who may need to make changes to the board device trees, though. Normal users also have legitimate reasons for tweaking the device tree of their board, such as:
Declaring external devices connected to board connectors. The simplest example is an I2C temperature sensor, but this can also include entire expansion boards plugged into the main board.
Changing the hardware blocks that are exposed on the external pins of their System on Chip. This is called Pin Multiplexing, and the Device Tree is the place where such multiplexing is configured.
Modifying operating system related properties, such as the Linux kernel command line or flash partitions.
In you have such a need, a first way to do this would be to directly modify the Device Tree for your hardware in the kernel sources, and recompile it. However, this is a rather bad idea because it will make it more difficult to upgrade to a later version of the kernel, possibly featuring changes to the Device Tree file you modified too. It’s always better not to tweak files maintained by others, and find a way to override them instead.
A second possibility to tweak the Device Tree for a board is to include it from a custom Device Tree for your own use case, using the /include/ statement from the Device Tree language, or #include and the C preprocessor. You can then use references to nodes in the original tree, using labels, and then modify the properties of such nodes or add new subnodes to them. It’s even possible to remove existing nodes and properties by using the /delete-node/ and /delete-property/ statements, as shown in the Device Tree Source Undocumented page.
However, this is still an inconvenient solution. Any time you plug in a new device or an expansion board, or want to tweak other settings, you have to rebuild and update the full Device Tree for your board. What if you could prepare Device Tree fragments for each change to make, compile them once for all, and then, when you boot your device, load the main Device Tree and only the fragments you need, without having anything else to recompile?
This is exactly what Device Tree Overlays are about. For example, in /lib/firmware, the Debian image shipped by BeagleBoard.org contains compiled Device Tree Overlays (DTBO) for the extension boards (also known as capes in the BeagleBoard world) they support, such as:
Then, at boot time, all you have to do is load the main DTB for your board, and then override it using the DTBOs corresponding to the capes which are currently mounted. Kernel contributors have also worked on solutions to load the DTBOs dynamically in the live system, but this solution is not mature yet. Therefore, the bootloader based solution at boot time remains so far the best one.
Writing Device Tree overlays
When the Device Tree overlays were first proposed, their syntax was very special and hard to remember. Fortunately, since version 1.5, the Device Tree compiler (dtc) supports a much more natural syntax for writing such overlays. For example, here are the sources for the overlay for the Relay cape, taken from the BBORG_RELAY-00A2.dts file in BeagleBoard.org’s Linux kernel tree:
This example shows us what is specific to Device Tree Overlay source code, compared to the normal Device Tree syntax:
Before any definition, the code must include the /plugin/; statement.
As in normal Device Tree code, you can refer to labels (such as &am33xx_pinmux in the above example), modify their properties, add or remove nodes and properties.
However, you cannot modify nodes which do not have a label. In this case, you have to recall such nodes by describing their absolute path from the root device between curly braces. There are two such instances in the above code: &{/chosen} and &{/}.
Compiling Device Tree overlays
Once you have the source code of the your overlay, it is supposed to be easy to compile it with the Device Tree Compiler. This time, let’s take the example of the BBORG_FAN-A000.dts overlay for the Fan cape, slightly modified:
The only change we made to this file was to replace __TIMESTAMP__ by a real timestamp. This statement is actually a macro meant to be substituted by the C Preprocesor before compiling with dtc.
This is where real life Device Tree overlay examples are getting more difficult to compile. Very simple overlays can be compiled with the above command, but as soon as the code contains #include statements or macros to be substituted by the C preprocessor, you have to call this preprocessor and give it the path to where the corresponding .h files are found in the kernel sources.
Fortunately, the kernel Makefile knows a suitable series of commands to compile such overlay sources.
Let’s clone BeagleBoard.org’s Linux kernel source tree. It contains Device Tree Overlays for most capes that are compatible with BeagleBoarg.org’s boards, and if I understood correctly, BeagleBoard.org’s kernel developers haven’t solved all the conflicts between their definitions and recent kernels yet. So, let’s checkout their 5.10 branch:
git clone https://github.com/beagleboard/linux.git
cd linux
git branch -a
git checkout 5.10
First, let’s install a toolchain, for example the one on Ubuntu:
sudo apt install gcc-arm-linux-gnueabihf
And then let’s prepare the environment for compiling the kernel:
Then, we can configure the kernel for the OMAP SoCs:
make omap2plus_defconfig
We also need to tweak the configuration for compiling the Device Trees and Overlays properly. So, run make menuconfig and set CONFIG_OF_OVERLAY=y. For the practical manipulations, you will also need to set CONFIG_LEDS_GPIO=y and CONFIG_LEDS_CLASS=y.
Device Tree Overlays are found in arch/arm/boot/dts/overlays/. You can compile them along with all normal DTBs with:
make dtbs
In case you want to recompile a specific DT overlay, for example the BBORG_RELAY-00A2.dts file:
$ touch arch/arm/boot/dts/overlays/BBORG_RELAY-00A2.dts
$ make dtbs
DTCO arch/arm/boot/dts/overlays/BBORG_RELAY-00A2.dtbo
Of course, for any of this to be useful at the end, you will also need to compile the kernel:
make -j8 zImage
Applying Device Tree overlays
As we already explained, U-Boot is the place where the Device Tree Overlays should be applied. To do this, here are the commands to run in U-Boot. As an example, we’re using the BeagleBone Black and its Relay Cape as example, assuming all the files where copied to the first partition of a micro-SD card, containing a FAT filesystem:
Allocate extra space for the DTB for future overlays, here adding 8192 bytes for example:
fdt resize 8192
Apply the overlay that we just loaded to the main DTB:
fdt apply 0x83000000
We are then ready to load the Linux kernel and boot it. Let’s see a more complete example…
Example usage on BeagleBone Black
You can of course follow this example, but you can also test it by yourself if you own the BeagleBone Black (or similar BeagleBone boards), and its Relay Cape.
Board setup
First, connect the Relay Cape to your board. In the below example, more capes are actually stacked, the Relay Cape being on top, as its volume doesn’t allow for further capes:
Then, take a microSD card and format its first partition with the FAT32 filesystem:
sudo mkfs.vfat -F 32 -n boot /dev/mmcblk0p1
Remove the microSD card and insert it again. It should now be mounted on /media/$USER/boot. Download an archive containing all the files you should need for the BeagleBone Black and its Relay Cape, and extract this archive in this mount point.
This archive contains U-Boot binaries for the BeagleBone Black, a DTB for the same board, Device Tree Overlays for BeagleBone capes under the overlays/ directory, and a kernel including its own root filesystem as an initramfs. This way, you don’t have to prepare another partition to hold the root filesystem. Note that the src/ subdirectory contains the Buildroot 2021.02 configuration to generate the root filesystem, as well as the Linux kernel configuration that we used.
To boot on U-Boot on the microSD card, press the USER button next to the USB host connector, when you power-up the board. Note that this is needed only once, until the board is completely switched off again. The board will continue to boot from the microSD card across reboots and resets. Make sure that the U-Boot prompt shows a 2021.07 U-Boot version.
Once in U-Boot, you can load the kernel, DTB and DTBO, apply the overlay as shown in the previous session:
You are now ready to boot your kernel with its updated Device Tree:
bootz 0x81000000 - 0x82000000
Then, log in with the root user and an empty password.
Checking from Linux that the overlay was applied
The first thing you can check is that the device tree overlay was indeed applied. You can do this by checking properties which are specific to the overlay, such as the one that was added to the chosen node (see the BBORG_RELAY-00A2.dts sources once again.
$ cd /proc/device-tree/chosen/overlays/
$ ls
BBORG_RELAY-00A2.kernel name
Our overlay specific property is there, but in a more general case, look for properties under /proc/device-tree which are specific to each overlay.
Testing the Relay cape
Have a look again at BBORG_RELAY-00A2.dts file. In particular, for each relay, it declares an LED which is controlled by the same GPIO:
Each LED is given a label that will correspond to a directory under /sys/class/leds:
# ls /sys/class/leds/relay-*
/sys/class/leds/relay-jp1:
brightness max_brightness subsystem uevent
device power trigger
/sys/class/leds/relay-jp2:
brightness max_brightness subsystem uevent
device power trigger
/sys/class/leds/relay-jp3:
brightness max_brightness subsystem uevent
device power trigger
/sys/class/leds/relay-jp4:
brightness max_brightness subsystem uevent
device power trigger
Since the each LED and associated relay are controlled by the same GPIO, this gives us a convenient interface to control the each relay. We just have to control the corresponding LED by using its interface in /sys/class/leds.
This may not be a generic solution to control relays, but it will be easier than having to use the libgpiod library and its associated tools.
Testing a relay for real
Now, let’s try to control Relay 3.
You are ready to connect a real circuit now. When the relay is inactive, the COM (Common) and NO (Normally Open) ports should be disconnected, while COM and NC (Normally Connected) should be connected. When you write 1 to the GPIO, the relay should then connect COM and NO:
The high voltage and low voltage parts of a relay are supposed to be separate and insulated, but in case their was a defect on my cape, I made my tests with a simple low-voltage circuit. However, relays are meant to be used for controlling normal AC voltages (110V / 230V).
Now, turn on Relay 3 by setting a non zero brightness on the corresponding LED:
echo 1 > /sys/class/leds/relay-jp3/brightness
You can turn the relay back off as follows:
echo 0 > /sys/class/leds/relay-jp3/brightness
Don’t hesitate to use this cape in your home automation projects!
What to remember
Device Tree Overlays are Device Tree fragments used to customize the Device Tree of a given board, typically to describe components added externally, including entire expansion boards, or tweak pin multiplexing. That’s the mechanism used by BeagleBoard.org’s kernel developers to support the numerous expansion boards (also known as capes) compatible with their boards. All you have to do is load the main Device Tree Binary for a board (DTB), and then load and apply Device Tree Overlay Binaries (DTBO).
Bootlin thanks BeagleBoard.org for funding the creation of this blog post. Note that more posts are coming in the next weeks, one about the BeagleBone Cape Interface Specification and one about the extension board manager we added to U-Boot.
Since the start of the pandemic in March 2020, we have been offering our popular training courses online to our customers, in both public sessions (opened to individual registration) and dedicated sessions (organized on-demand for our customers, at their choice of date/time).
Our public sessions were initially all organized in the afternoon of Europe (14:00 to 18:00 Paris time), but we started in late 2021 proposing our Embedded
Linux system development training course for customers in the US/America, especially on the West Coast. Thanks to the success of this, we have decided to also start offering at times convenient for US/America customers the following courses:
our Linux kernel driver development training course. The first session is scheduled from April 11 to April 21, with Bootlin engineer and trainer Miquèl Raynal, who is also a maintainer in the Linux kernel! The course runs from 09:00 AM to 1:00 PM Pacific, 12:00 PM to 4:00 PM Eastern, 6:00 PM to 10:00 PM Europe. Registration at the discount rate until March 10 for 829 EUR.
our Yocto/OpenEmbedded system development training course. The first session is scheduled from March 7 to March 10, with Bootlin engineer and trainer Maxime Chevallier. The course runs from 09:00 AM to 1:00 PM Pacific, 12:00 PM to 4:00 PM Eastern, 6:00 PM to 10:00 PM Europe. Registration at the discount rate is available until February 6 for 519 EUR.
The chosen time is ideal for US/America customers, but also works for participants in Europe who would like to attend our courses outside of their normal working hours.
Of course, we have plenty of other training sessions scheduled, for all our 7 different training courses, covering a wide range of time zones. Check our training page for all the details, and contact us if you have specific needs: a dedicated training course for your company, a session organized at a different date/time, etc.
Linux 5.16 has been released on January 9. As usual, our recommended reading to learn more about this release is the corresponding Kernelnewbies.org page and the two articles from LWN covering the 5.16 merge window: part 1 and part 2.
As usual, Bootlin contributed a number of patches to this release, with a total of 117 commits, making Bootlin the 22th contributing company according to statistics (Unknown and Hobbyists not counting as companies).
Here are the main highlights of our contributions to 5.16:
Alexandre Belloni, as the maintainer of the RTC subsystem, continued to improve the core subsystem and RTC drivers. He added a new user-space interface to RTC to allow getting/settings RTC parameters. It is used to get the features of an RTC from user-space, to get/set the RTC correction or to configure Backup Switch Mode. In addition, Alexandre made various improvements to several RTC drivers, such as adding Backup Switch Mode, and general refactoring.
Clément Léger did a small fix in the clock drivers for Microchip ARM platforms, fixing an issue discovered as part of his work porting OP-TEE to Microchip ARM platforms.
Hervé Codina made some fixes to the fsmc NAND controller driver, which is used on a number of old platforms from ST. They fix support of certain NAND chips on those platforms. These issues were discovered as part of the development of a Linux BSP for an old ST Spear320 platform.
Maxime Chevallier fixed a deadlock in the network stack, that was causing the kernel to stop booting when using a root filesystem over NFS combined with the network interface using a SFP module.
Miquèl Raynal contributed many improvements to the max1027 ADC driver in the IIO subsystem, supporting hardware triggers.
Miquèl Raynal contributed support for the ADC found on Texas Instruments AM437x platforms. This required significant changes in the MFD driver that is used to support the multiple features of this ADC, as well as improvements in the existing IIO driver for TI ADCs.
Paul Kocialkowski contributed a small addition enabling the Rockchip VPU on Rockchip PX30 platforms, and merged the Device Tree bindings for the logiCVC display controller (but not yet the driver itself).
2021 has come to an end, a year that everyone will most likely consider as somewhat complicated and unusual, even though the current situation seems to now becoming the new normal. The switch to a new year is generally a good moment to take a step back, and review what happened in the past year, and draw some directions for the coming year.
In this blog post, we’d like to do exactly this for Bootlin, which has seen a number of significant changes this year, as well as a continuation of its usual activities.
We also take this opportunity to wish you all an happy year 2022, and send you our best wishes. May 2022 be full of interesting projects and also be a safe year for everyone.
Here are the main topics that we cover in this lengthy blog post:
One major change for Bootlin in 2021 is that the company was acquired by Thomas Petazzoni, former CTO, and Alexandre Belloni. So it’s an internal acquisition, by former employees, meaning that Bootlin has kept the same offering and spirit. Further, Bootlin’s original founder Michael Opdenacker is still in the team, but now as an employee. See our blog post regarding the acquisition, back in February.
In 2021, we also recruited several engineers, bringing significant additional expertise to our team:
Thomas Perrot, who joined just before the start of 2021, bringing 10 years of experience in embedded Linux BSP development, with a strong Yocto expertise.
Hervé Codina, who joined in March 2021, bringing 20+ years of experience in bare-metal and Linux embedded development.
Clément Léger who joined in June 2021, bringing 10 years of experience in Linux kernel development, including the expertise on porting the Linux kernel to a brand new CPU architecture.
We continue to have open positions for embedded Linux engineers, and we plan to hire 3 to 4 engineers in 2022, hiring for the first time engineers located outside of France.
Engineering projects
As is the case every year, our engineering team has been kept busy this year mostly by our engineering projects, all focused on our core expertise of low-level embedded Linux development.
We have selected below a few highlights of our work in 2021, in various areas.
Build systems
Apart from delivering numerous BSPs based on Yocto or Buildroot to our customers, we have also directly contributed to both the Yocto and Buildroot open-source projects.
On the Yocto Project side:
Bootlin engineer Michael Opdenacker has become one of the co-maintainers of the official Yocto Project documentation, making numerous improvements and contributions to this documentation. See our blog post on this topic. We will continue this involvement in the Yocto Project documentation in 2022.
Bootlin engineer and COO Alexandre Belloni has been active in the build and release engineering effort of the Yocto Project, as a member of the Yocto Project SWAT team. Alexandre has been working directly with the main Yocto Project architect, Richard Purdie, on the review and validation of new contributions. Other Bootlin engineers have also helped in investigating and resolving specific bugs. We will also continue this involvement in the Yocto Project build engineering in 2022.
On the Buildroot side:
We have continued our work towards the implementation of top-level parallel build support in Buildroot. Bootlin engineer Hervé Codina has posted several iterations of a patch series bringing a mechanism preventing file overwrites between packages, a requirement for proper top-level parallel build.
We implemented and published, in partnership with ST, a Buildroot BR2_EXTERNAL called buildroot-external-st which contains example configurations for the STM32MP1 platforms from ST.
We contributed support for hybrid ISO9660 images, supporting in a single image PC platforms based on legacy BIOS, 32-bit UEFI BIOS and 64-bit UEFI BIOS, using the grub2 bootloader.
We helped one of our customers reduce their out-of-tree Buildroot patches by upstreaming a number of new Buildroot packages.
Outside of our the Yocto Project and Buildroot, we also ventured into the world of Debian/Ubuntu for embedded systems, by using the ELBE tool, to which we contributed support for building Ubuntu-based images. See our blog post that describes how to use ELBE to automatically build Ubuntu-based images for the Raspberry Pi.
Audio support in Linux
Audio support in the Linux kernel is another area where Bootlin engineers have specific expertise with. Here are some examples of audio related projects we worked on in 2021:
Integration of audio support for an i.MX6 platform with a complex dual AD1978 audio codec configuration, with a TDM8 audio interface between the SoC and the audio codecs.
Development of a brand new and complete ALSA driver for a new PCIe sound card, based on a FPGA.
Integration of audio support for an i.MX8 platform used in the automotive space with a complex audio configuration that involves multiple A2B transceivers through the Analog Devices AD2428 A2B master, Bluetooth audio, and more.
OP-TEE
In 2021, we started working on a major project: adding support for the Microchip SAMA5D2 processor to the OP-TEE project. This project is already well underway, as we have a functional port of OP-TEE, which is now being upstreamed.
As part of this, Bootlin engineer Clément Léger has implemented and contributed a generic clock framework for OP-TEE, which has already been accepted upstream. See our blog post for more details.
Clément also gave a talk at the Embedded Linux Conference 2021 on the topic of OP-TEE, titled OP-TEE: When Linux Loses Control. Slides and video are available.
We expect to continue the upstreaming of the SAMA5D2 support in 2022, and also develop support for additional SAM5D2 hardware capabilities in OP-TEE.
U-Boot extension board manager
In collaboration with the BeagleBoard.org community, we developed and contributed to U-Boot a generic extension board manager. This mechanism allows hardware platforms such as the BeagleBone to automatically detect extension boards that are connected, and apply the Device Tree overlays that provide the hardware description for those extension boards.
This work was covered in detail in the talk given by Bootlin engineer Köry Maincent at the Live Embedded Event in June 2021, see the slides and video.
Modems
In 2021, we had the opportunity to work on several projects that involved 3G/4G/5G modems, strengthening our knowledge of the modem stack in Linux, especially around modem-manager, libmbim and libqmi.
For example, we worked on the support of a Quectel BG95 modem interfaced with a RaspberryPi 4, or the support of a Sierra Wireless EM9190 modem interfaced over PCIe to an NXP i.MX6. The latter was particularly challenging and is still on-going, as the upstream Linux support for PCIe 5G modems is still very recent. We contributed a few fixes in this area.
Secure boot
Secure boot remains an important topic for a growing number of projects, and in 2021, we helped customers with secure boot on several i.MX6 platforms, and on one i.MX8 platform. The Yocto integration of secure boot was also a key aspects in those projects, to get a proper process for signing and verifying all states of the boot process. We also have a few U-Boot contributions in our contribution pipeline related to improving secure boot support. See for example the talk from Thomas Perrot at Live Embedded Event, relating the secure boot setup on i.MX8.
Camera, ISP and video support
We finished 2020 with a lot of on-going contributions to the Linux Video4Linux subsystem, which we had summarized in a blog post early 2021. In particular, our drivers for the OV5568 and OV8865 camera sensors were merged upstream.
In 2021, Bootlin engineer and multimedia expert Paul Kocialkowski continued to work on several multimedia topics. Some of the key projects included:
Optimizing the H264 decode → rescale → H264 encode pipeline of one of our customers, on an Allwinner H3 platform. We were able to significantly optimize the pipeline by leveraging the H264 decoder built into the Allwinner processor, for which Paul had written a Linux kernel driver several years ago, and by developing a custom ffmpeg plugin that offloaded the rescaling to the GPU, using the open-source lima support. A fully open-source solution!
Developing a proper Linux kernel driver for the Allwinner ISP, with support for debayering and noise filtering. This was a significant challenge as the Allwinner ISP was so far only supported through closed-source binary blobs. We have already submitted a first iteration to the upstream Linux kernel community. See our blog post for more details, as well as the talk given by Paul at the Embedded Linux Conference: slides and video.
Improving the Allwinner Linux kernel camera driver to support single buffer capture. This is useful in scenarios where camera sensors are not used to capture a sequence of frames, but just single frames, and the available memory is limited. This is particularly true on platforms such as the Allwinner V3s, which may be limited to just 64MB of RAM. This is going to be submitted upstream soon, as part of our on-going work on the Allwinner camera driver.
NAND and flash support
With Bootlin engineer Miquèl Raynal being a maintainer of the NAND subsystem in Linux and a co-maintainer of the MTD subsystem, it should be no surprise that we have continued to deal with a number of flash memory related projects in 2021:
We have brought in mainline the support for several NAND flash controllers:
For the Arasan NAND controller, used in some Xilinx processors. See our blog post on this topic.
For the ARM Primecell PL35x NAND controller, used in some other Xilinx processors. See our blog post on this topic.
For the NAND controller found at least in the the Renesas R-Car Gen3 and RZ/N1 processors.
Contributed support for the NV-DDR interface, which is used by some NAND flash chips and controllers to increase the throughput. See our blog post.
Continued our work on generalizing ECC support in the MTD subsystem, so that all ECC setups (software ECC, on-die ECC, ECC in the NAND controller, or external ECC engine) can be supported regardless of the NAND interface (serial or parallel). See the talk from Miquèl Raynal, ECC engines given at last year’s ELCE.
Improved the TI GPMC NAND controller driver to properly support NAND chip with large pages (larger than 4KB).
ADC/IIO support
We’ve helped a few customers with Linux kernel support for ADC devices, namely:
Extend the support for the MAX1027 family of ADCs, with support for external triggers
Bring support for the ADC found in TI AM437x processors
All of these were contributed to the upstream Linux kernel, Miquèl Raynal also wrote a extensive blog post on various aspects of the IIO subsystem and has taken the opportunity of these projects to also improve/clarify various aspects of the IIO core in a recent patch series.
Networking
Networking support in the Linux kernel is also one area where Bootlin is very active. Here are some key projects we worked on in 2021, some of them being on-going with additional work expected in 2022:
We implemented support for PTP offloading for the Qualcomm AR803X PHY.
We started working on QUSGMII support in Linux, a new standard that allows PTP time-stamps to be included directly on the preamble of QSGMII frames.
We started working on the 802.15.4 stack in the Linux kernel, with our initial step being support for passive scanning.
We implemented mqprio support in the mvneta Linux kernel driver, used for some Marvell platforms. mqprio is a queuing discipline that allows mapping traffic flows to hardware queue ranges using priorities and a configurable priority to traffic class mapping.
We implemented Frame DMA support in the Ocelot Ethernet switch driver, significantly improving the performance of frame injection/extraction by the CPU into/from the switch traffic.
We developed proper SFP support in Linux and U-Boot, with dynamic reconfiguration (in Linux only), for a customer using the Zynq 7000 platform and a complex network setup.
BSP development
Many of our projects are obviously related to the development of update of complete Linux BSP for our customers (bootloader, Linux kernel, custom embedded Linux distribution). Here are a few examples:
Development of a brand new U-Boot, Linux and Yocto based BSP to migrate an existing product running Windows CE on a ST Spear320 processor to Linux. This sort of development proved to be challenging as the Spear320 support in both U-Boot and Linux is close to be abandoned (and in fact has since then been removed from U-Boot upstream). We hope to be able to contribute to improve the upstream Spear320 support in 2022.
Migration of an AM335x/Buildroot based BSP to newer Linux kernel and Buildroot releases, for a customer in the healthcare industry
On-going migration of an i.MX6 BSP from an old kernel release and a custom build-system to recent versions of U-Boot and Linux as well as a proper standardized Yocto Project based Linux distribution. This project presents some interesting challenges as it uses only one of the two Cortex-A9 cores to run Linux, the other one runs a bare-metal application, and we will also migrate this to a proper usage of the remoteproc and rpmsg mechanisms.
We worked with several customers on STM32MP1 platforms, helping with porting on new platforms, extending the Device Tree and device drivers, developing custom Yocto-based or Buildroot-based distributions. STM32MP1 is definitely becoming a popular platform for a number of new projects.
We also worked with several customers on custom platforms based on the RasberryPi Compute Module, doing Device Tree configuration/tweaking and Yocto integration.
Over-the-Air update integration
We continued to help our customers with the integration of Over-The-Air update solutions in their embedded Linux systems. A few examples:
We integrated RAUC for an i.MX6 platform, using the Barebox bootloader and Yocto Project based distribution. Bootlin engineer Kamel Bouhara wrote a detailed blog post on this topic, as well as the talk from Kamel at Live Embedded Event
We integrated the Azure Device Update for IoT Hub, using the U-Boot bootloader on a RaspberryPi CM4 platform, also with a Yocto Project based distribution. Internally, the Device Update for IoT Hub is based on swupdate
As part of a migration of an existing embedded product based on Debian to a Yocto-based distribution, we are integrating Mender.
Crédit Impôt Recherche
For our French customers, another important milestone achieved by Bootlin in 2021 is the delivery of our Crédit Impôt Recherche agreement, which allows our French customers to benefit from tax incentives on research and development activities done by Bootlin for their projects. See our blog post for more details.
Training
With the COVID19 still making travel conditions difficult and uncertain, most of our training activity in 2021 was dedicated to on-line training courses. Indeed, 69 out of our 72 training sessions were delivered online this year. In total, we delivered our training courses to 906 engineers in 2021.
Just like all our other training courses, the complete training materials for those new courses are freely available, distributed under the CC-BY-SA license.
Another major event in 2021 was our work to get the French Qualiopi certification, which proves the quality of our training organization and processes. As part of this, we have improved several aspects of our training courses, mainly regarding feedback collection and handling as well as the evaluation of the participants.
In 2022, we expect to at least:
Improve how our online course are delivered, by ensuring more participants can do the practical labs by themselves, which is an important part of the learning process
Publish at least one more training course. We already have plans for a course on a topic that we think will be very relevant to many embedded Linux engineers. Stay tuned for updates on this!
Have additional capacity to deliver our training courses, which are seeing significant demand.
For more details about our training offering, see our training page, which details our dedicated on-line and on-site sessions as well as our public on-line sessions.
Contributions
In Bootlin continued and strong open-source focus, we once again contributed to different open-source projects in 2021:
Linux kernel. The best summaries are our blog posts about our contributions to Linux 5.10, Linux 5.11, Linux 5.12, Linux 5.13, as well as Linux 5.14 and 5.15. Some of our significant contributions: huge effort on ECC engine support in the MTD subsystem, rv3032 RTC driver, support for new MIPS platforms from Microchip, a Simple Audio Mux driver, major work on timer/TCB support on Microchip ARM platforms, new I3C master controller driver for the Silvaco I3C IP, new drivers for the OV5568 and OV8865 camera sensors, NAND controller drivers for the Arasan, PL35x and Renesas IPs, enabling of ADC support on TI AM437x.
U-Boot. Our biggest contribution has been the extension board manager, which is described earlier in this blog post. We also contributed various small fixes and improvements.
OP-TEE. We contributed a generic clock framework, and the support for the SAMA5D2 clock tree and TRNG driver. So far 55 commits from Bootlin have been integrated in OP-TEE.
Buildroot. We contributed a total of 257 patches. The main contributions are in the area of tooling to list security vulnerabilities in Buildroot packages, support for Bootlin external toolchains, improved SELinux support, support for the Beagle-V RISC-V platform, a good number of new packages, support for hybrid ISO9660 images. In addition, Thomas Petazzoni continued his work as a co-maintainer of the project: Thomas has reviewed and merged close to 2000 patches from Buildroot contributors throughout 2021.
Yocto Project. As outlined above in this blog, we did major contributions to the Yocto Project, with Michael Opdenacker becoming co-maintainer of the Yocto Project documentation, and Alexandre Belloni being involved in the build and release engineering effort.
Linux Test Project. We fixed a number of issues in LTP tests that prevented from using LTP in embedded-oriented systems, such as the ones that can be generated using the Yocto Project. See our blog post for more details.
Our training materials, which are all freely available, have seen no less than 872 commits. These includes updates to our existing training courses, but also our new Real-Time Linux with PREEMPT_RT training course.
Here are the talks that we presented this year, at various virtual events:
FOSDEM 2021
Networking Performance in the Linux Kernel, Getting the most out of the Hardware, by Maxime Chevallier. Slides and video.
Embedded Linux from scratch in 45 minutes, on RISC-V, by Michael Opdenacker. slides and video.
Live Embedded Event
Security vulnerability tracking tools in Buildroot, by Thomas Petazzoni. Slides and video.
Secure boot in embedded Linux systems, by Thomas Perrot. Slides and video.
Understanding U-Boot Falcon Mode, by Michael Opdenacker. Slides and video.
Device Tree overlays and U-Boot extension board management, by Köry Maincent. Slides and video.
Getting started with RAUC, by Kamel Bouhara. Slides and video.
Embedded Linux Conference
I3C in tomorrow’s design, by Miquèl Raynal. Slides and video.
Embedded Linux nuggets found in Buildroot package Eldorado, by Michael Opdenacker. Slides and video.
OP-TEE: When Linux Loses Control, by Clément Léger. Slides and video.
Advanced Camera Support on Allwinner SoCs with Mainline Linux, by Paul Kocialkowski. Slides and video.
A webinar organized in partnership with ST, Device Tree 101, by Thomas Petazzoni. Slides and video.
A webinar organized in partnership with Microchip, Improving Linux Boot Time in Your Embedded Application, with the participation of Thomas Petazzoni. Link.