72 cores, 3 dias, y una linea: la batalla por la GPU de una Raspberry Pi 3 en NixOS


27 de marzo de 2026

Esta es la historia de como tardamos 3 dias en activar una GPU en una Raspberry Pi 3. No porque sea dificil, sino porque NixOS y el firmware de la Pi no se ponen de acuerdo en quien manda sobre el hardware. Y de como la solucion fue comentar una linea.

El problema

La Raspberry Pi 3 tiene una GPU VideoCore IV (vc4). En Raspbian funciona de serie. En NixOS, no. RetroArch iba a 1 fps. Software rendering puro. La GPU estaba ahi pero nadie la usaba.

$ cat /sys/firmware/devicetree/base/soc/gpu/status
disabled

$ cat /sys/class/drm/card0/device/uevent
DRIVER=simple-framebuffer

$ lsmod | grep vc4
vc4    442368  0    <-- cargado pero 0 referencias, no engancha

El modulo del kernel vc4 se cargaba, pero con cero referencias. No encontraba hardware. El device tree tenia la GPU en disabled.

Por que pasa esto

El boot de una Raspberry Pi es una cadena:

1. GPU firmware (start.elf) arranca
   |
   v
2. Lee config.txt
   |  -> dtoverlay=vc4-fkms-v3d  (activa GPU en el device tree)
   v
3. Prepara DTB con overlays aplicados
   |  -> gpu: status = "okay"
   v
4. Carga u-boot (bootloader de NixOS)
   |
   v
5. u-boot lee extlinux.conf
   |  -> FDTDIR ../nixos/kernel-dtbs/  <-- AHI ESTA EL PROBLEMA
   v
6. u-boot SOBREESCRIBE el DTB del firmware con el del kernel
   |  -> gpu: status = "disabled" (vuelta al principio)
   v
7. Linux arranca con GPU desactivada

El firmware de la Pi hace su trabajo correctamente: lee el overlay vc4-fkms-v3d, lo aplica al device tree, y le pasa un DTB con la GPU activada a u-boot. Pero u-boot tiene la directiva FDTDIR en extlinux.conf, que le dice "ignora ese DTB y carga el del kernel". Y el DTB del kernel tiene la GPU en disabled porque nadie le aplico el overlay.

Es un conflicto de autoridad: el firmware dice "GPU ON", u-boot dice "me da igual, uso mi DTB".

Lo que intentamos (y fallo)

Intento 1: Cargar el modulo vc4 por fuerza

boot.kernelModules = [ "vc4" ];

Resultado: el modulo se carga pero con 0 referencias. No encuentra hardware porque el device tree dice disabled. El modulo no es el problema.

Intento 2: DTS overlay via NixOS

hardware.deviceTree = {
  enable = true;
  filter = "bcm2710-rpi-3-b.dtb";
  overlays = [{
    name = "enable-vc4";
    dtsText = ''
      /dts-v1/; /plugin/;
      / { fragment@0 { target-path = "/soc/v3d@7ec00000";
          __overlay__ { status = "okay"; }; }; };
    '';
  }];
};

Resultado: rompio el boot. La Pi no arrancaba. El script de NixOS que aplica overlays al DTB fallo con FDT_ERR_BADOFFSET. Tuvimos que revertir con extlinux desde el disco conectado a aurin.

Intento 3: Modificar el DTB manualmente

Decompilamos el DTB con dtc, cambiamos disabled por okay en los nodos v3d, gpu y hdmi, recompilamos, y lo pusimos en la particion firmware.

Resultado: u-boot ignora el DTB de la particion firmware. Usa el de FDTDIR.

Lo pusimos en el directorio de FDTDIR (/boot/nixos/kernel-dtbs/).

Resultado: sigue disabled. NixOS monta esos ficheros desde el nix store (inmutable). Nuestro DTB modificado fue ignorado.

Intento 4: Cambiar a armv7l (32 bits)

La GPU vc4 supuestamente no funciona en aarch64 (64 bits) en la Pi 3. Probamos compilar todo el sistema en armv7l.

Resultado: bun y otros paquetes de home-manager no soportan armv7l. Errors de Unsupported system en cascada. Volvimos a aarch64.

Intento 5: simpledrm.disable=1 y video=simplefb:off

Desactivar el simple framebuffer que se apodera de la GPU antes de que vc4 pueda probar.

Resultado: simpledrm esta compilado como builtin en el kernel (no como modulo). Los parametros de modulo no afectan a builtins. Sigue cargandose primero.

Intento 6: nixos-raspberrypi (kernel vendor)

El paquete nixos-raspberrypi promete un kernel vendor con firmware y device tree gestionados.

Resultado: 8 horas de compilacion cross-aarch64 via QEMU. 72 cores de Dual Xeon E5-2699v3 al 100% toda la noche. El kernel compilo, pero el script de instalacion fallo porque la particion firmware tenia solo 30MB (necesitaba mas). Y cuando funciono, el FDTDIR en extlinux seguia sobreescribiendo el DTB.

La solucion: una linea

Despues de 3 dias y 6 intentos fallidos, la solucion fue comentar una linea en /boot/extlinux/extlinux.conf:

 LABEL nixos-default
   LINUX ../nixos/kernel-Image
   INITRD ../nixos/kernel-initrd
   APPEND init=/nix/store/...-nixos-system/init ...
-  FDTDIR ../nixos/kernel-dtbs
+#  FDTDIR ../nixos/kernel-dtbs

Sin FDTDIR, u-boot no sobreescribe el DTB. Usa el que el firmware preparo con el overlay vc4-fkms-v3d aplicado. La GPU se activa.

$ cat /sys/firmware/devicetree/base/soc/gpu/status
okay

$ ls /dev/dri/
by-path  card1  renderD128

$ lsmod | grep vc4
vc4    442368  3    <-- 3 referencias, ENGANCHADO

$ cat /sys/class/drm/card*/device/uevent
DRIVER=vc4-drm

Una linea. 3 dias. 8 horas de compilacion. 6 intentos fallidos.

El diagrama: por que tarda 8 horas compilar

Aurin (x86_64)                          Raspberry Pi 3 (aarch64)
Dual Xeon E5-2699v3                     BCM2837 ARM Cortex-A53
72 threads, 128GB RAM                   4 cores, 1GB RAM
========================                ========================

nix build .#retropix.sdImage
     |
     v
QEMU aarch64 emulacion
(cada instruccion ARM se
 traduce a x86 por software)
     |
     +-- gcc cross-compile kernel
     |   6.12.47 (millones de lineas C)
     |   ~4 horas
     |
     +-- compilar 353 overlays DTB
     |   ~10 minutos
     |
     +-- compilar modulos kernel
     |   ~2 horas
     |
     +-- compilar firmware vendor
     |   ~30 minutos
     |
     +-- generar imagen SD (ext4 + zstd)
     |   ~1 hora
     |
     v
resultado: 12GB .img.zst
tiempo total: ~8 horas

Si tuvieramos un Mac Studio M5 Ultra:
- 16 cores nativos ARM a 4.5 GHz
- Sin emulacion QEMU
- Estimacion: ~20 minutos

La emulacion QEMU es el cuello de botella. Cada instruccion ARM que gcc genera para el kernel tiene que ser traducida por QEMU a x86, ejecutada en el Xeon, y el resultado traducido de vuelta. Son capas sobre capas sobre capas.

72 cores ayudan en paralelo (make -j72), pero la IPC emulada es ~10x mas lenta que nativa. Un M5 Ultra con ARM nativo haria esto en minutos.

Lo que queda por hacer

La solucion funciona pero es fragil: cada nixos-rebuild regenera extlinux.conf y restaura el FDTDIR. Hay que volver a comentarlo despues de cada deploy.

La solucion definitiva seria:

  1. Que nixos-raspberrypi genere DTBs con vc4 enabled por defecto
  2. O que el bootloader NO use FDTDIR y deje al firmware gestionar el device tree
  3. O parchear el script de generacion de extlinux para omitir FDTDIR en la Pi

Pero por hoy, la GPU funciona. RetroArch va con aceleracion hardware. Xenogears va a correr como en una PlayStation de verdad. Y hemos aprendido mas sobre el boot de una Raspberry Pi de lo que jamas quisimos saber.

Leccion

A veces la solucion no es anadir codigo, sino quitar una linea. Tres dias buscando que anaddir: modulos, overlays, kernels, builds de 8 horas. Y al final era quitar 40 caracteres.

#  FDTDIR ../nixos/kernel-dtbs

Esa linea comentada es el resultado de 72 cores x 3 dias x 6 intentos. Es la linea mas cara que he escrito.

Dedicado a todos los que han peleado con device trees a las 3 de la manana. No estais solos.

Comparte este post:

Es tu post

Estas seguro? Esto no se puede deshacer.

Comentarios (0)

Sin comentarios todavia. Se el primero!

Deja un comentario