NixOS on ARM/Raspberry Pi 4

From NixOS Wiki
Jump to: navigation, search
Raspberry Pi 4 Family
(Image not available)
Manufacturer Raspberry Pi Foundation
Architecture AArch64
Bootloader Custom or U-Boot
Boot order Configurable; SD, USB, Netboot
Maintainer
Raspberry Pi 4B
SoC BCM2711

The Raspberry Pi family of devices is a series of single-board computers made by the Raspberry Pi Foundation. They are all based on Broadcom System-on-a-chip (SoCs).

Status

The Raspberry Pi 4 Family is only supported as AArch64. Use as armv7 is community supported.

Board-specific installation notes

First follow the generic installation steps to get the installer image and install using the installation and configuration steps.

The Raspberry Pi 4B works with the generic SD image.

Sample instructions for installing NixOS on a Raspberry Pi are available at nix.dev.

Configuration

Using nixos-generate-config will not generate the required minimal configuration.

For better GPU Support, remember to add the nixos-hardware channel: nixos-hardware https://github.com/NixOS/nixos-hardware/archive/master.tar.gz

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
{ config, pkgs, lib, ... }:

{
 # This configuration worked on 09-03-2021 nixos-unstable @ commit 102eb68ceec
 # The image used https://hydra.nixos.org/build/134720986

  boot = {
    kernelPackages = pkgs.linuxPackages_rpi4;
    tmpOnTmpfs = true;
    initrd.availableKernelModules = [ "usbhid" "usb_storage" ];
    # ttyAMA0 is the serial console broken out to the GPIO
    kernelParams = [
        "8250.nr_uarts=1"
        "console=ttyAMA0,115200"
        "console=tty1"
        # A lot GUI programs need this, nearly all wayland applications
        "cma=128M"
    ];
  };

  boot.loader.raspberryPi = {
    enable = true;
    version = 4;
  };
  boot.loader.grub.enable = false;

  # Required for the Wireless firmware
  hardware.enableRedistributableFirmware = true;

  networking = {
    hostName = "nixos-raspi-4"; # Define your hostname.
    networkmanager = {
      enable = true;
    };
  };

  nix = {
    autoOptimiseStore = true;
    gc = {
      automatic = true;
      dates = "weekly";
      options = "--delete-older-than 30d";
    };
    # Free up to 1GiB whenever there is less than 100MiB left.
    extraOptions = ''
      min-free = ${toString (100 * 1024 * 1024)}
      max-free = ${toString (1024 * 1024 * 1024)}
    '';
  };
  system.stateVersion = "20.09";
}

USB boot

For USB booting to work properly, a firmware update might be needed:

 $ nix-shell -p raspberrypi-eeprom
 $ rpi-eeprom-update -d -a

Now reboot the device so it can update the firmware from boot partition.

When running from USB device without SD card present, kernel spams log about missing SD card, workaround for this is to set:

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
{
  boot.loader.raspberryPi.firmwareConfig = "dtparam=sd_poll_once=on";
}

GPU support

The following configuration samples are built on the assumption that they are added to an already working configuration. They are not complete configurations.

Without GPU

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
{
  services.xserver = {
    enable = true;
    displayManager.lightdm.enable = true;
    desktopManager.gnome3.enable = true;
    videoDrivers = [ "fbdev" ];
  };
}

With GPU

In nixos-hardware#261 a new option has been added to use the fkms-3d overlay. This will only work with the vendor kernel.

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
{ pkgs, ... }:

{
  imports = [
    .../nixos-hardware/raspberry-pi/4
  ];

  hardware.raspberry-pi."4".fkms-3d.enable = true;

  services.xserver = {
    enable = true;
    displayManager.lightdm.enable = true;
    desktopManager.gnome3.enable = true;
  };
}

Tools

The raspberry tools are available in the libraspberrypi package and include commands like vcgencmd to measure temperature and CPU frequency.

Audio

In addition to the usual config, you will need to enable audio support explicitly in the firmwareConfig.

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
  sound.enable = true;
  hardware.pulseaudio.enable = true;

  boot.loader.raspberryPi.firmwareConfig = ''
    dtparam=audio=on
  '';


Gpio

Add gpio group and change permission for all users in new gpio group. Now all users in gpio group have access to /dev/gpiomem and to gpio pins via sysfs.


Breeze-text-x-plain.png
/etc/nixos/configuration.nix
  # add gpio group
  users.groups.gpio = {};

  # udev rule for gpio
  services.udev.extraRules = ''
    SUBSYSTEM=="bcm2835-gpiomem", KERNEL=="gpiomem", GROUP="gpio",MODE="0660"
    SUBSYSTEM=="gpio", KERNEL=="gpiochip*", ACTION=="add", RUN+="${pkgs.bash}/bin/bash -c 'chown root:gpio  /sys/class/gpio/export /sys/class/gpio/unexport ; chmod 220 /sys/class/gpio/export /sys/class/gpio/unexport'"
    SUBSYSTEM=="gpio", KERNEL=="gpio*", ACTION=="add",RUN+="${pkgs.bash}/bin/bash -c 'chown root:gpio /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value ; chmod 660 /sys%p/active_low /sys%p/direction /sys%p/edge /sys%p/value'"
  '';

  # add user with gpio group
  users = {
    mutableUsers = false;
    users.mygpiouser = {
      isNormalUser = true;
      password = "mygpiouserpasswd";
      extraGroups = [ "wheel" "gpio" ];
    };
  };


HDMI-CEC

A few bits and pieces for using HDMI-CEC on the Pi4:

Breeze-text-x-plain.png
/etc/nixos/configuration.nix
{ pkgs, ... }:

{
  # an overlay to enable raspberrypi support in libcec, and thus cec-client
  nixpkgs.overlays = [
    (self: super: { libcec = super.libcec.override { inherit (self) libraspberrypi; }; })
  ];

  # install libcec, which includes cec-client (requires root or "video" group, see udev rule below)
  # scan for devices: `echo 'scan' | cec-client -s -d 1`
  # set pi as active source: `echo 'as' | cec-client -s -d 1`
  environment.systemPackages = with pkgs; [
    libcec
  ];

  services.udev.extraRules = ''
    # allow access to raspi cec device for video group (and optionally register it as a systemd device, used below)
    SUBSYSTEM=="vchiq", GROUP="video", MODE="0660", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/dev/vchiq"
  '';

  # optional: attach a persisted cec-client to `/run/cec.fifo`, to avoid the CEC ~1s startup delay per command
  # scan for devices: `echo 'scan' > /run/cec.fifo ; journalctl -u cec-client.service`
  # set pi as active source: `echo 'as' > /run/cec.fifo`
  systemd.sockets."cec-client" = {
    after = [ "dev-vchiq.device" ];
    bindsTo = [ "dev-vchiq.device" ];
    wantedBy = [ "sockets.target" ];
    socketConfig = {
      ListenFIFO = "/run/cec.fifo";
      SocketGroup = "video";
      SocketMode = "0660";
    };
  };
  systemd.services."cec-client" = {
    after = [ "dev-vchiq.device" ];
    bindsTo = [ "dev-vchiq.device" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      ExecStart = ''${pkgs.libcec}/bin/cec-client -d 1'';
      ExecStop = ''/bin/sh -c "echo q > /run/cec.fifo"'';
      StandardInput = "socket";
      StandardOutput = "journal";
      Restart="no";
  };
}


Notes about the boot process

Unless using an extremely early WIP image, the Raspberry Pi 4B boots using the U-Boot platform firmware.

Updating U-Boot/Firmware

 
$ nix-shell -p raspberrypi-eeprom
$ mount /dev/disk/by-label/FIRMWARE /mnt
$ BOOTFS=/mnt FIRMWARE_RELEASE_STATUS=stable sudo -E rpi-eeprom-update -d -a
source

Troubleshooting

Power issues

The Raspberry Pi 4B is as power-hungry, if not more, as its predecessors. It is important to have a sufficient enough power supply or weirdness may happen. Weirdness may include:

  • Lightning bolt icon on HDMI output "breaking" the display.
  • Screen switching back to u-boot text
    • Fixable temporarily when power is sufficient by switching VT (alt+F2 / alt+F1)
  • Random hangs
Note: A properly rated USB power supply, AND a good cable are necessary. The cable has to be short enough to not incur power losses through the length. Do note that thin and cheap cables usually have thinner copper wires, which in turn accentuates power losses.

Note that the Type-C USB receptacle for the Raspberry Pi 4B does not implement Power Delivery (USB PD). This means that it is limited to whatever the power supply will provide when not negotiating power, which is most likely 5V at some undetermined power level.