Read the Full Series
This article is one part of a walkthrough detailing how we recreated an NXP i.MX 8M Mini–based computer using Quilter’s physics-driven layout automation.
Building Firmware for an AI-Laid-out Computer: From Boot to Google Meet (Part 5/5)
Project Speedrun is our challenge to design a complete computer using our physics-driven AI as quickly as possible. This blog series documents how that system was developed and the engineering decisions behind it. Start with the Project Speedrun overview and its results.
Parts 1 through 4 covered the PCB design: preparing the schematic, running Quilter, cleaning up the output, and validating the hardware under real workloads. Both boards came back from Sierra Circuits, powered on immediately, and booted Linux on the first attempt.
That proved the layout worked. This post covers what it took to make the Speedrun board feel like a real computer.

The Spec
Project Speedrun was never meant to produce a board that just passed electrical tests. The goal, as Sergiy put it early in the project:
"It has to boot to a desktop, run Chromium, and join a Google Meet call. I want to host a demo and at the end say, 'oh, and by the way, I'm talking to you on this computer right now.'"
That set a clear bar. The Speedrun computer had to:
- Run Linux with a user-friendly desktop environment.
- Run the Chromium browser with hardware-accelerated video.
- Join a live Google Meet call with camera and audio.
- Look and behave like a computer someone would actually want to use.
None of those requirements are trivial on a quad-core ARM Cortex-A53 with a Vivante GLES 2.0 GPU. Every one of them forced real firmware engineering decisions.
Why the Software Matters for the Hardware Story
A PCB that passes power-on testing is a necessary milestone. A PCB that runs a Google Meet call is proof that the layout actually works under sustained, real-world conditions: stable DDR4 at speed, reliable USB and MIPI interfaces, functional audio paths, and a power delivery network that holds up under load.
Every software feature described in this post exercises a different part of the hardware Quilter designed. The Chromium browser hammers the memory subsystem and GPU interface. Video encode and decode stress the VPU bus and power rails. Audio playback validates the codec routing. Even Doom, which we included partly for fun, pushes the GPU and frame buffer in ways that a simple test pattern never would.
The firmware isn't separate from the hardware validation. It is the hardware validation.
The Build System: Yocto and the NXP BSP
NXP supports the i.MX 8M Mini through a Yocto Board Support Package (BSP) based on the Walnascar (6.12) release. Yocto is the standard build framework for embedded Linux on NXP application processors. It assembles a complete Linux image from "recipes" that define how each package is configured, patched, and compiled.
The stock NXP image ships Weston as its compositor, includes Qt demo apps, and uses RPM packaging. It's designed to showcase silicon features, not to be a usable desktop. To meet the Speedrun spec, we needed to replace the entire desktop stack.
We did this by creating a custom Yocto layer called meta-quilter, set to priority 99 so it overrides NXP defaults. The layer contains all the recipes, patches, and configuration needed to transform the stock BSP into the Speedrun image. Thanks especially to Brandin Claar of remodulate LLC for helping put this recipe together.
Here's what changed from stock:
Nearly every row in that table required patching, configuration overrides, or workarounds for the Vivante GPU. The stock BSP is designed around the Weston compositor and NXP's demo applications, so running a full GNOME desktop means going well beyond the reference configuration.
The Desktop: GNOME 48 on a Vivante GPU
We chose GNOME because it's what most Linux users recognize. A Weston session with terminal windows and Qt demos doesn't meet the bar of "a computer someone would actually want to use." GNOME gives you a task bar, a file manager, a system tray, and the expectation of a familiar desktop.
Getting there required solving a real problem. The Vivante GC NanoUltra only supports GLES 2.0, and Mutter (GNOME's compositor) assumes GLES 3.0+ in several code paths. Earlier builds using Mutter 46 suffered from persistent screen flickering caused by Mutter's multi-GPU detection. The i.MX 8M Mini has a split DRM architecture: one device for the LCDIF display controller, another for the Vivante GPU. Mutter treated this as a multi-GPU system and kept fighting itself over which card to render to.
Upgrading to Mutter 48, which includes upstream triple buffering, resolved the flickering. But running GNOME 48 on GLES 2.0 still required a set of targeted workarounds:
- Forcing GTK4 to use the Cairo renderer instead of its GL backend, which calls GLES 3.0 functions the Vivante driver doesn't support.
- Setting COGL and Clutter to use the GLES2 driver explicitly.
- Injecting a stub EGL Mesa extension header into the Mutter build. Mutter 48 unconditionally includes a Mesa-specific header that Vivante EGL doesn't provide.
- Relaxing type-compatibility warnings in gnome-session because Vivante's EGL native types differ from Mesa's.
The result is a responsive GNOME 48 desktop running on Wayland with GLES2 rendering. You log in through GDM, open a file manager, launch a terminal, and interact with the system exactly as you would on a standard Linux desktop.
The Hard Part: Chromium and Hardware Video
Chromium was the centerpiece of the Speedrun spec. Without it, you can't join a Google Meet call, and the mic-drop demo doesn't happen.
Getting Chromium to launch on the Speedrun board was the easy part. NXP already provides 22 patches in their BSP for Chromium's V4L2 video decode pipeline, covering the Amphion and Hantro decoders, HEVC support, G2D integration, and NV12 zero-copy. With those patches, Chromium 129 runs on Wayland/Ozone and can play back video using the hardware decoders.
But decoding video is only half of a video call. Google Meet also requires the local camera feed to be encoded and transmitted to other participants. That's the encode path, and NXP's patches don't cover it.
The i.MX 8M Mini includes a Hantro H1 hardware video encoder, but Chromium has no built-in support for V4L2 hardware encoding on this class of device. WebRTC, Chromium's real-time communication stack, defaults to software VP8 or VP9 encoding. On a Cortex-A53 at 1.8 GHz, software encode at meeting-quality resolution is too slow for real-time use.
We wrote 3 custom Chromium patches to solve this:
Patch 1: V4L2 MMAP hardware encode. This is the main patch, touching 8 Chromium source files. It forces V4L2 to use MMAP memory type for the Hantro H1 encoder, adds stride-aware buffer copying, removes the VP9 software encoder to force hardware codec selection, prioritizes hardware formats in WebRTC negotiation, and disables the low-resolution software fallback that would otherwise bypass the hardware path.
Patch 2: Codec debug flags. Adds CLI flags like --webrtc-disable-vp8 and --webrtc-disable-h264 so we could isolate codec issues during development. When you're debugging why a video call drops frames, being able to force a specific codec path saves hours.
Patch 3: GLES 2.0 null-pointer fix. Chromium's GPU extension enumeration calls glGetStringi, which is a GLES 3.0+ function. On the Vivante driver, this function pointer is NULL. Chromium doesn't check for NULL before calling it because it assumes GLES 3.0 minimum. Our patch installs a safe stub at initialization time. The fix had to go in the driver binding layer because thin LTO inlines across compilation units, make call-site guards insufficient.
With all 3 patches applied, Chromium runs on the Speedrun board with hardware-accelerated video decode and encode. The board can join a Google Meet call, transmit camera video, and receive remote participants' video, all rendered through the hardware pipeline.
Boot Sequence and Branding
We wanted the Speedrun board to feel finished from the moment you power it on, not like a development board running a hacked-together image. The boot sequence reflects that:
U-Boot displays a Quilter splash logo and reports "Project Speedrun" in the device tree model string. The kernel boots quietly with suppressed console output and deferred framebuffer console takeover. Plymouth takes over from U-Boot with a spinner animation and Quilter watermark on the DRM/KMS display. Finally, GDM presents a login screen. The default user is "speedrun" and the hostname is "speedrun."
These branding touches required U-Boot logo replacement, device tree string modification, kernel command-line configuration to suppress messages and enable Plymouth, and systemd drop-ins to coordinate the handoff between Plymouth and GDM. Small details, but they're the difference between a demo and a product.
The Fun Stuff: Doom, Quake, and Media Playback
Not everything on the Speedrun board is strictly necessary. Some of it is there because we could, and because it makes the demo more memorable.
GZDoom with Freedoom WADs. A full Doom engine running on the Vivante GLES2 renderer. Freedoom provides open-source game content for both Episode 1 and Episode 2. If your AI-designed computer can run Doom, that's a certain kind of proof-of-concept that resonates with engineers.
Quake. An SDL-based GLES1 port, patched for GCC 14 compatibility. Another classic that exercises the GPU in different ways than Doom.
mpv and ffmpeg. Both built with V4L2 M2M hardware decode, so the Hantro VPU handles video decompression rather than burning CPU cycles on software decode. mpv is configured to force the OpenGL API because the Vivante Vulkan ICD is broken.
Firefox 147. A pre-built ARM64 binary installed alongside Chromium, giving the system a second browser for general browsing.
PulseAudio. Audio support, configured for the EVK Line-Out jack via the WM8524 codec. The stock BSP comes with PulseAudio but it had to be enabled for GNOME.
Extending the BSP
A significant portion of the meta-quilter layer exists to adapt the BSP for a use case it wasn't originally configured for. This is normal for embedded Linux development. Silicon vendor BSPs are optimized for their reference configurations, and the moment you push beyond that baseline (say, by running GNOME instead of Weston), you encounter assumptions that need adjusting.
Some examples: the stock BSP disables PulseAudio and X11 support in GTK3 because the default Weston configuration doesn't need them. Running GNOME means re-enabling both. A systemd patch included in the BSP targets an earlier systemd version and conflicts with 257.6. An upstream Unicode license file changed its checksum between releases. The bundled libdisplay-info version predates what Mutter 48 requires.
The meta-quilter layer addresses each of these with targeted bbappend files. Two BSP source files also need direct patching because they use Yocto's :remove operator, which can't be overridden from a downstream layer. The full list of adaptations is documented in the GitHub repository.
Open Source
The complete firmware recipe is public. The repository includes the meta-quilter Yocto layer, all custom patches, build configuration files, and a step-by-step build guide. If you have an i.MX 8M Mini EVK (or the Speedrun board), you can reproduce the entire image from source.
Repository: https://github.com/xjordanx/speedrun
We published this for the same reason we publish the Speedrun PCB design files: transparency builds trust. Engineers can inspect the firmware the same way they can inspect the layout. Every patch, every workaround, every build flag is visible.
What the Software Proves About the Hardware
Parts 1 through 4 of this series documented a layout process that compressed 428 quoted hours into 38.5 hours of human effort. That's the efficiency story. This post is the capability story.
The Speedrun board runs a GNOME 48 desktop with hardware-accelerated Chromium, joins live video calls, plays Doom, decodes video through the hardware VPU, and streams audio over Bluetooth. It does this on boards that Quilter designed, fabricated at Sierra Circuits, that booted on the first spin.
None of this software would work if the underlying layout had signal integrity issues, power delivery problems, or routing errors in the high-speed interfaces. The firmware isn't a layer on top of the hardware story. It's the final, most demanding test of whether the AI-designed layout actually holds up.
It does.




















