Raspberry-Pi-CM3

Adding Raspberry Pi CM3 support to Debian Buster

Introduction

Since the initial launch in 2012, many Raspberry Pi models have been released. Leaving older versions 1 and 2 aside, one can mention those more recent models:

  • Raspberry Pi 3 Model A+ (November 2018)
  • Raspberry Pi 3 Model B (February 2016)
  • Raspberry Pi 3 Model B+ (March 2018)
  • Raspberry Pi 4 Model B (June 2019)

Below: what a Raspberry Pi 4 Model B looks like (credit: www.raspberrypi.org).

Pi 4 Model B
Raspberry Pi 4 Model B

In addition to those single-board devices, some Computer Module (CM) models are available. Their form factor is slightly different and aims at making it possible to embed them into industrial products.

Below: a few pictures of a Raspberry Pi CM3 (click for full view).

Pi CM3, front Pi CM3, back
Pi CM3, front Pi CM3, back
Pi CM3 (bottom) compared to Pi 3 (top)
1

>> Check the Raspberry Pi website for more details about the Compute Module 3.

For development purposes, it can be mounted on a development kit called the Compute Module IO Board V3. This breakout board exposes many ports, including GPIO pins, HDMI, and USB.

Below: what a Compute Module IO Board V3, without or with a mounted Raspberry Pi CM3, looks like (click for full view).

IO Board V3 (left) and Pi CM3 (right) IO Board V3 with mounted Pi CM3
Compute Module IO Board V3 (left) and Pi CM3 (right) Compute Module IO Board V3 with mounted Pi CM3

>> Check the Raspberry Pi website for more details about the Compute Module IO Board V3.

This article aims at documenting some specifics of this kind of hardware, and Debamax’s contributions to make the Raspberry Pi CM3 usable on Debian systems.

Possible support in Debian Buster

It was already established that Debian Buster ships with all the required pieces to support “regular” Raspberry Pi 3 devices. Thanks to the work of the Debian Raspberry Pi Maintainers, it is rather easy to prepare a Debian image to run on the target device.

Specifically, the Raspberry Pi image specs repository contains various YAML-based recipes that can be used as-is or modified to tweak the configuration a little. This includes being able to add or remove some packages, tweak users and passwords, locales, etc. Here’s a direct link to the raspi3.yaml file. This recipe is to be used with the vmdb2 tool, that will produce an image ready to be copied onto the Raspberry Pi.

Note: It’s possible to build an arm64 image from an amd64 machine as the architecture-specific steps can be performed within QEMU. There’s also a caching mechanism making it possible to avoid re-doing lengthy steps in case someone needs a few tries to get the right settings.

Unfortunately, while an image built from the stock raspi3.yaml configuration file boots fine on a Raspberry Pi 3, that’s not the case for a Raspberry Pi CM3.

Why is that? The hardware is mostly the same, and the Linux kernel contains appropriate code to support it. But it also needs to know what components are available, how they are wired, etc. Such configuration can be made available through a so-called device tree. The bootloader (e.g. U-Boot) can look for a particular, hardware-specific file containing a compiled version (DTB) and hand it over to the Linux kernel so that the latter knows about the actual hardware setup.

The main takeaway is that while a single Linux kernel image can be used on many different devices, one has to make sure there’s a DTB available for this specific device… And as of August 2019, that’s the main difference between the regular Raspberry Pi 3 and the Raspberry Pi CM3 version. The former needs bcm2837-rpi-3-b.dtb or bcm2710-rpi-3-b-plus.dtb, shipped in the linux-image-<ABI> package on arm64, while the latter has a bootloader that expects bcm2710-rpi-cm3.dtb, which is lacking in the initial Buster release (versioned 10.0). Thankfully, Debian stable releases get updated through point releases and adding hardware support might be feasible!

Linux kernel support

The device tree blobs are built from the Linux kernel source, from a variety of *.dts and *.dtsi files. The difference between those two file extensions is a technical detail regarding reusability: one can include some other file to avoid repeating the same contents in many different files. That can happen when devices vary very slightly (see below).

The Linux kernel in Buster is based on the 4.19.y series, and support for the Raspberry Pi CM3 was first released in Linux v4.20-rc1 upstream tag. The needed patches are the following:

  1. ARM: dts: add Raspberry Pi Compute Module 3 and IO board
  2. arm64: dts: broadcom: Add reference to Compute Module IO Board V3
  3. arm64: dts: broadcom: Use the .dtb name in the rule, rather than .dts

Let’s break it down…

  • The first patch touches the arch/arm/boot/dts directory, which is the device tree source directory for 32-bit ARM. It builds a new target named bcm2837-rpi-cm3-io3.dtb, from a source file named bcm2837-rpi-cm3-io3.dts. This source file reuses an existing file (bcm283x-rpi-usb-host.dtsi) through the include mechanism, but also a new file added by the same commit: bcm2837-rpi-cm3.dtsi.
  • The second patch touches the arch/arm64/boot/dts directory, which is the device tree source directory for the 64-bit ARM port. It builds a new target named bcm2837-rpi-cm3-io3.dts, by reusing bcm2837-rpi-cm3-io3.dts that was added in the first patch, through the include mechanism once again.
  • The third patch is just a fix-up commit as the target name added under arch/arm64 was misspelled: the actual target name is bcm2837-rpi-cm3-io3.dtb.

Those patches were quite small and mostly additions, so backporting them to the 4.19.y kernel in Buster was trivial. There could have been conflicts in the Makefile but that part didn’t change between both versions anyway.

To generate an updated linux-image-<ABI> for arm64, a quick way is to cross-build it from a fast amd64 host. The following was sufficient for this use case:

DEB_BUILD_OPTIONS="nocheck nodoc" DEB_BUILD_PROFILES="pkg.linux.notools cross nopython" debuild --no-lintian -aarm64 -B -j8 -nc

Once the build finishes, a number of binary packages are available in the parent directory: <pre> linux-headers-4.19.0-6-arm64_4.19.67-2_arm64.deb linux-image-4.19.0-6-arm64-unsigned_4.19.67-2_arm64.deb linux-image-4.19.0-6-arm64-dbg_4.19.67-2_arm64.deb linux-headers-4.19.0-6-all-arm64_4.19.67-2_arm64.deb linux-headers-4.19.0-6-all_4.19.67-2_arm64.deb linux-config-4.19_4.19.67-2_arm64.deb linux-libc-dev_4.19.67-2_arm64.deb linux-image-arm64-signed-template_4.19.67-2_arm64.deb </pre> <p>Note: For more details about the unsigned and signed-template packages, see this article: An overview of Secure Boot in Debian.

The resulting linux-image-4.19.0-6-arm64-unsigned binary contains those Raspberry Pi DTBs accordingly:

./usr/lib/linux-image-4.19.0-6-arm64/broadcom/bcm2837-rpi-3-b-plus.dtb
./usr/lib/linux-image-4.19.0-6-arm64/broadcom/bcm2837-rpi-3-b.dtb
./usr/lib/linux-image-4.19.0-6-arm64/broadcom/bcm2837-rpi-cm3-io3.dtb

and the third one is indeed what the 3 backported patches were supposed to be achieving. All good?

raspi3-firmware support

Unfortunately, there’s still one part missing: that extra DTB file needs to be made available where the bootloader expects it. This means being available under the /boot/firmware directory. Moreover, it has to be named bcm2710-rpi-cm3.dtb as mentioned in the introduction section, rather than bcm2837-rpi-cm3-io3.dtb as built and shipped in the Linux image package.

Copying the DTB is taken care of by the raspi3-firmware package, and by its /etc/kernel/postinst.d/z50-raspi3-firmware hook specifically. Excerpt:

if [ "$KERNEL" = "auto" ]; then
  pi0w_dtb=${dtb_path}/bcm2835-rpi-zero-w.dtb
  pi1ap_dtb=${dtb_path}/bcm2835-rpi-a-plus.dtb
  pi1bp_dtb=${dtb_path}/bcm2835-rpi-b-plus.dtb
  pi2b_dtb=${dtb_path}/bcm2836-rpi-2-b.dtb
  pi3b_dtb=${dtb_path}/bcm2837-rpi-3-b.dtb
  pi3bp_dtb=${dtb_path}/bcm2837-rpi-3-b-plus.dtb

  [ -e "${pi0w_dtb}"  ] && cp "${pi0w_dtb}"  /boot/firmware/bcm2835-rpi-zero-w.dtb
  [ -e "${pi1ap_dtb}" ] && cp "${pi1ap_dtb}" /boot/firmware/bcm2835-rpi-a-plus.dtb
  [ -e "${pi1bp_dtb}" ] && cp "${pi1bp_dtb}" /boot/firmware/bcm2835-rpi-b-plus.dtb
  [ -e "${pi2b_dtb}"  ] && cp "${pi2b_dtb}"  /boot/firmware/bcm2709-rpi-2-b.dtb
  [ -e "${pi3b_dtb}"  ] && cp "${pi3b_dtb}"  /boot/firmware/bcm2710-rpi-3-b.dtb
  [ -e "${pi3bp_dtb}" ] && cp "${pi3bp_dtb}" /boot/firmware/bcm2710-rpi-3-b-plus.dtb

Two important things can be noted here:

  • Thanks to the test on the existence of the various DTB files, the firmware package can cope with different linux-image-<ABI> packages, which might or might not ship any given DTB file.
  • There’s also a renaming going on for some of the DTBs. One can read about the details in this Raspberry Pi StackExchange entry.

Adding an extra variable and an extra if/cp call makes it possible to get the extra DTB copied under the expected name.

Is that all? Yes! Patching the raspi3.yaml file to install the patched linux-image-<ABI> and raspi3-firmware packages leads to an image which contains the DTB in the right place and under the right name; the bootloader finds it and then the Pi CM3 boots up just fine!

Contributions

Following the usual Upstream first! mantra, Cyril checked the Documentation/process/stable-kernel-rules.rst and it seemed that a DTB addition would fit the “New device IDs and quirks are also accepted.” criterion. So a small patch series was submitted for inclusion into the 4.19.y stable tree so that it would flow downstream to Debian at some point, but that was deemed not to be suitable for stable upstream.

That’s why Cyril resorted to submitting a merge request against the linux source package in Debian to get that fixed downstream: sid: Please add DTB support for Rasperry Pi Compute Module 3; this was promptly merged by Vagrant Cascadian, and released to unstable in version 4.19.37-6.

Since the buster uploads didn’t integrate those patches, a new merge request against the buster branch was submitted as well: buster: Raspberry Pi CM3 support; this was merged by Ben Hutchings, and later uploaded to buster-proposed-updates.

On the raspi3-firmware side, the packaging repository is open to contributions by all Debian Developers, so Cyril pushed the Add support for bcm2837-rpi-cm3-io3.dtb aka. bcm2710-rpi-cm3.dtb commit to the master branch directly.

With a green light from Romain Perier, Cyril also prepared a buster-proposed-updates bug report against release.debian.org: #935386: buster-pu: package raspi3-firmware/1.20190215-1+deb10u1. That is the standard procedure to request approval from the Stable Release Managers to update a package in a stable release. There was a little glitch though, as the patched version didn’t enter unstable immediately, and having bugfix or improvements available there is a usual requirement from the Stable Release Managers. This slight delay in getting the updated package into unstable was due to the source and binary packages getting renamed from raspi3-firmware to raspi-firmware (as mentioned above, Raspberry Pi 4 models are available now), hence the need for a review through the NEW queue. <p>Without surprises, both the linux and raspi3-firmware packages were approved by the Stable Release Managers, and were made available in the buster-proposed-updates suite. They were then merged into the official buster suite during the 10.1 point release, which happened on 2019-09-08.

The following table sums up which packages are needed to get support for Raspberry Pi CM3.

stable (buster) unstable (sid)
linux 4.19.67-2 4.19.37-6 and above
raspi*-firmware raspi3-firmware 1.20190215-1+deb10u1 raspi-firmware 1.20190718-1

Executive summary: Since the 10.1 point release, the Raspberry Pi CM3 is officially supported in buster and above! Its evolution, the Raspberry Pi Compute Module 3+ (CM3+), is supported as well.