The Ramblings Of A Coder by Omer Anson

Fedora 33 on Dragonboard 410c

16 Feb 2021

In this post, I describe how to get Fedora 33 Server running on the Dragonboard 410c board.

A while back we got some Dragonboard 410c boards0. The code we developed was tested on Fedora 33, and I didn’t feel like porting it to Debian or Fedora 29, which work out-of-the-box on this board. Getting Fedora 33 to work on it seemed much more interesting.

Step 1 - Compilation!

The first step is to compile and install the kernel. I installed the cross-compilation tools for armv8 (aarch64). Since I use Fedora 33 on my development machine, I just ran dnf install gcc-aarch64-linux-gnu.

Next, I downloaded the latest kernel version from Linaro1. It has been modified to work on the Dragonboard 410C. The latest version, as of this time of writing, is aligned with Linux 5.9.9.

For the most part, I have followed the instructions in 2, with minor modification.

Firstly, download the kernel source code. Note that the following command automatically checks out branch debian-qcom-dragonboard410c-20.11. This was the latest branch at the time of writing. See 2 to check if there’s a newer version.

git clone http://git.linaro.org/landing-teams/working/qualcomm/kernel.git -b debian-qcom-dragonboard410c-20.11 kernel-dragonboard

The code has been downloaded into kernel-dragonboard. If this takes too long, you can add --depth 1 to avoid downloading the git history.

Next, the default configuration has to be modified. Apply the following patch:

diff --git a/kernel/configs/distro.config b/kernel/configs/distro.config
index f7dc7c00a72d..f84bcec8347b 100644
--- a/kernel/configs/distro.config
+++ b/kernel/configs/distro.config
@@ -189,6 +189,10 @@ CONFIG_EXT3_FS_SECURITY=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_ONLINE_SCRUB=y
 CONFIG_TMPFS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_TMPFS_XATTR=y

This adds support for the xfs file system, as it is configured in the stock Fedora 33 kernel. This is the file system used in the ready-to-use Fedora 33 Server aarch64 image.

Next, set the following environment variables:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

Note that in CROSS_COMPILE, if the cross-compiler binaries (e.g., aarch64-linux-gnu-gcc) are not in your path, you should provide a full path to them.

Create a kernel configuration from the modified default configuration:

make defconfig distro.config

Compile the kernel image, the Device Tree Blob, and the kernel modules:

make -j$(nproc) Image.gz dtbs modules KERNELRELEASE=5.9.0-qcomlt-arm64

Next, install the kernel modules to some location. You will need them later.

make modules_install KERNELRELEASE=5.9.0-qcomlt-arm64 INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=<directory>

That’s it for compilation. The kernel image is in arch/arm64/boot/Image.gz, the device tree blobs are in kernel/arch/arm64/boot/dts/qcom. There are a bunch there, but it also includes the correct one for the Dragonboard 410c board. There is no initrd image yet. We still need to create that.

Step 2 - initrd

I created an initrd image with dracut. I figured this would work best for Fedora. Running dracut works best when ran from the same image and architecture as the target. So first off, hop over to 3, and download Fedora 33’s aarch64 raw image. This blog post was tested with the Server edition.

Once you have the raw image, it might be best to start by making a copy of it, as we are going to edit it. Start a Virtual Machine with the image. Make sure that the virtual machine uses it as its disk, and doesn’t create a copy or overlays it in some way, or converts it to a different format. Using virt-manager with libvirt gave me some good results.

Don’t forget that the architecture is aarch64. You may need to install some additional packages for it, such as qemu-system-aarch64.

Once the VM is up and running, copy the compiled kernel modules to /lib/modules/. I created a tar archive:

MODDIR=<INSTALL_MOD_PATH directory given in the make modules_install step>
cd $MODDIR/lib/modules
tar -zcf /tmp/5.9.0-qcomlt-arm64.tar.gz 5.9.0-qcomlt-arm64

Do not make the mistake of archiving and extracting the entire tree. There is some symbolic tree magic that breaks when you do that. And then the VM is unusable. And then you spend the long seconds it takes to restore the copy considering your life choices. You made a copy, right?

Once the archive has been copied to the VM (e.g., using scp, or shared directories), you can extract it:

tar -zxf <path to archive> -C /lib/modules/

We will need to tell dracut that we need additional modules. This is because all the device manager modules are built into the kernel in Fedora, but are built as kernel modules in our kernel’s default configuration.

Create the file /etc/dracut.conf.d/dragonboard.conf with the following content:

add_drivers+=" dm_mirror dm_region_hash dm_log dm_mod xfs "

Note the spaces around the module names, including the first and last one.

You may also want to give root a temporary or empty password. This password will be used when the initrd image drops into a rescue shell. By default the root account is locked and has no password. Leaving it like this means that the rescue shell is effectively inaccessible. passwd -u root to set a password, or passwd -d root to clear the password. Run passwd -l root to lock the account again when you are done.

Once ready, run sudo dracut /tmp/initrd-dragonboard.img. This will work for a while. Cross-architecture virtual machines are painfully slow. Once complete, copy the image back to the host, using scp or something.

Stage 3 - Create Boot Image

To create the boot image, you will need to clone the skales repository for android bootloaders4:

git clone https://us.codeaurora.org/quic/kernel/skales

This is the one recommended by the Dragonboard 410c documentation. I also read the code and saw that they match in terms of what the bootloader expects versus what the image utility creates. Which does not match the android bootloader header 100%. There are minor differences.

Firstly, you will need to pack the device tree blobs.

skales/dtbTool -o dtb-dragonboard-5.9 kernel-dragonboard/arch/arm64/boot/dts/qcom

Note that you may have to fiddle with the directory locations. I assume you cloned skales and the kernel into the same directory.

Once done, we can create a boot image. The following command line creates it in linux-5.9.img:

skales/mkbootimg --kernel=kernel/arch/arm64/boot/Image.gz --output=linux-5.9.img --dt=dtb-dragonboard-5.9 --pagesize 2048 --base 0x80000000 --ramdisk=initrd-dragonboard.img --cmdline="root=/dev/mapper/fedora_fedora-root ro rd.lvm.lv=fedora_fedora/root rhgb quiet mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_hx8394d_720p_video:1:none "

You can add the following options to increase debugging and to use the serial console: console=ttyMSM0,115200n8 debug earlycon rd.shell. Setting up the serial console is described here 5.

You will also need to write the main Fedora 33 image to a micro-SD or USB stick. Use the one from the VM, where the kernel modules were installed. Otherwise, the modules may be missing and some things won’t work. Once done, insert the micro-SD or USB stick into the device.

To test the boot image, connect the device to your computer using the micro-USB port. Power on the device while pressing the volume down (-) button on the device. It is the middle small black button next to the host USB ports. This will start the device in fastboot.

You can verify the device is started in fastboot by running the following:

sudo fastboot devices

You may need to install the fastboot package for this to work.

You should see output similar to the following:

451f3c38	fastboot

To test the new boot image without writing it to the device, run

sudo fastboot boot linux-5.9.img

If this works well, you can repeat the process and flash the image to the device. It will then boot without fastboot:

sudo fastboot flash boot linux-5.9.img

Step 4: Troubleshooting

First, note that these instructions are for Fedora 33 Server. The workstation version would need minor modification. At the very least, the workstation version uses brtfs and not xfs. I also haven’t managed to get the HDMI display to work. Everything is done using the serial console.

I ran into a few problems. This is how I got around them:

Firstly, if the kernel refuses to boot, or refuses to see the block devices on the SD or USB storage devices, verify you are using the correct kernel. That is, make sure you are using the kernel from 1.

If it fails to find the Device Tree Blob (DTB), verify you have used dtbTool to convert the directory to a file, and passed --dt to mkbootimg. Verify also that you are using mkbootimg from the skales repo, and not the one provided by Fedora.

If the initrd fails to start the shell, make sure you ran dracut from a matching architecture (e.g., using an aarch64 VM).

Next, via the rescue shell, you can run blkid. It should show you some partitions on /dev/mmcblk0p<X>, and your partitions on /dev/mmcblk1p<X>. In case of a USB, your partitions will show up as /dev/sda<X>, or something similar.

If you don’t, and your image is on a USB stick, try again with the computer disconnected. That is, disconnect the micro-USB cable from the board. The USB controller on the board cannot be a device (micro-USB port active) and host (two USB ports active) at the same time.

Supposing this works, you can also run lvm_scan. You should get something similar to the following:

sh-5.0# lvm_scan
Scanning devices mmcblk1p3  for LVM logical volumes fedora_fedora/root
ACTIVE '/dev/fedora_fedora/root' [5.41 GiB] inherit
sh-5.0#

mmcblk1p3 will probably be replaced by the LVM partition on your SD or USB drives.

If the above works, then your storage is visible. If mounting fails, make sure you can load the xfs kernel module. lsmod lists all loaded modules, so you can verify it is there.

Lastly, journalctl -xe is your friend. If something doesn’t work, you should review the logs there to try and understand what failed.

Conclusion

It wasn’t easy. A lot of work has gone into getting this board to work. The important thing to remember is to use their kernel. It has been customised to work on their board.

Notice that u-boot and grub are not used here. I didn’t need it, and this way seemed faster. It has its drawbacks. For starters, the size of the boot image is limited to 64 megabytes.

I’ll also note that your mileage may vary. I went through a lot of trial and error to get this working. It’s possible that I forgot to mention one or two steps.