mirror of
https://github.com/nix-community/raspberry-pi-nix.git
synced 2025-11-08 19:46:03 +01:00
294 lines
9.2 KiB
Markdown
294 lines
9.2 KiB
Markdown
# raspberry-pi-nix
|
|
|
|
The primary goal of this flake is to make it easy to create
|
|
working NixOS configurations for Raspberry Pi products. Specifically,
|
|
this repository aims to deliver the following benefits:
|
|
|
|
1. Configure the kernel, device tree, and boot loader in a way that is
|
|
compatible with the hardware and proprietary firmware.
|
|
2. Provide a nix interface to Raspberry Pi/device tree configuration
|
|
that will be familiar to those who have used Raspberry Pi's
|
|
[config.txt based
|
|
configuration](https://www.raspberrypi.com/documentation/computers/config_txt.html).
|
|
3. Make it easy to build an image suitable for flashing to an sd-card,
|
|
without the need to first go through an installation media.
|
|
|
|
The important modules are `overlay/default.nix`, `rpi/default.nix`,
|
|
and `rpi/config.nix`. The other modules are mostly wrappers that set
|
|
`config.txt` settings and enable required kernel modules.
|
|
|
|
## Example
|
|
|
|
See [the example
|
|
repo](https://github.com/tstat/raspberry-pi-nix-example) for a
|
|
complete example.
|
|
|
|
```nix
|
|
{
|
|
description = "raspberry-pi-nix example";
|
|
nixConfig = {
|
|
extra-substituters = [ "https://raspberry-pi-nix.cachix.org" ];
|
|
extra-trusted-public-keys = [
|
|
"raspberry-pi-nix.cachix.org-1:WmV2rdSangxW0rZjY/tBvBDSaNFQ3DyEQsVw8EvHn9o="
|
|
];
|
|
};
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
|
|
raspberry-pi-nix.url = "github:tstat/raspberry-pi-nix";
|
|
};
|
|
|
|
outputs = { self, nixpkgs, raspberry-pi-nix }:
|
|
let
|
|
inherit (nixpkgs.lib) nixosSystem;
|
|
basic-config = { pkgs, lib, ... }: {
|
|
time.timeZone = "America/New_York";
|
|
users.users.root.initialPassword = "root";
|
|
networking = {
|
|
hostName = "basic-example";
|
|
useDHCP = false;
|
|
interfaces = { wlan0.useDHCP = true; };
|
|
};
|
|
environment.systemPackages = with pkgs; [ bluez bluez-tools ];
|
|
hardware = {
|
|
bluetooth.enable = true;
|
|
raspberry-pi = {
|
|
config = {
|
|
all = {
|
|
base-dt-params = {
|
|
# enable autoprobing of bluetooth driver
|
|
# https://github.com/raspberrypi/linux/blob/c8c99191e1419062ac8b668956d19e788865912a/arch/arm/boot/dts/overlays/README#L222-L224
|
|
krnbt = {
|
|
enable = true;
|
|
value = "on";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
in {
|
|
nixosConfigurations = {
|
|
rpi-example = nixosSystem {
|
|
system = "aarch64-linux";
|
|
modules = [ raspberry-pi-nix.nixosModules.raspberry-pi basic-config ];
|
|
};
|
|
};
|
|
};
|
|
}
|
|
```
|
|
|
|
## Using the provided cache to avoid compiling linux
|
|
This repo uses the raspberry pi linux kernel fork, and compiling linux
|
|
takes a while. I do push my kernel builds to a cachix cache that you
|
|
may use to avoid compiling linux yourself. The cache can be found
|
|
at https://raspberry-pi-nix.cachix.org, and you can follow the
|
|
instructions there to use this cache.
|
|
|
|
You don't need the cachix binary to use the cachix cache though, you
|
|
just need to add the relevant
|
|
[`substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=nix.conf#conf-substituters)
|
|
and
|
|
[`trusted-public-keys`](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=nix.conf#conf-trusted-public-keys)
|
|
settings settings to your `nix.conf`. You can do this directly by
|
|
modifying your `/etc/nix/nix.conf`, or in the flake definition. In the
|
|
above example flake these `nix.conf` settings are added by the
|
|
`nixConfig` attribute ([doc
|
|
link](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html?highlight=flake#flake-format)).
|
|
Note that this will only work if the user running `nix build` is in
|
|
[`trusted-users`](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=nix.conf#conf-trusted-users)
|
|
or the substituter is in
|
|
[`trusted-substituters`](https://nixos.org/manual/nix/stable/command-ref/conf-file.html?highlight=nix.conf#conf-trusted-substituters).
|
|
|
|
## Building an sd-card image
|
|
|
|
An image suitable for flashing to an sd-card can be found at the
|
|
attribute `config.system.build.sdImage`. For example, if you wanted to
|
|
build an image for `rpi-example` in the above configuration
|
|
example you could run:
|
|
|
|
```
|
|
nix build '.#nixosConfigurations.rpi-example.config.system.build.sdImage'
|
|
```
|
|
|
|
## The firmware partition
|
|
|
|
The image produced by this package is partitioned in the same way as
|
|
the aarch64 installation media from nixpkgs: There is a firmware
|
|
partition that contains necessary firmware, u-boot, and
|
|
config.txt. Then there is another partition (labeled `NIXOS_SD`) that
|
|
contains everything else. The firmware and `config.txt` file are
|
|
managed by NixOS modules defined in this package. Additionally, a
|
|
systemd service will update the firmware and `config.txt` in the
|
|
firmware partition __in place__. Linux kernels are stored in the
|
|
`NIXOS_SD` partition and will be booted by u-boot in the firmware
|
|
partition.
|
|
|
|
## `config.txt` generation
|
|
|
|
As noted, the `config.txt` file is generated by the NixOS
|
|
configuration and automatically updated on when the nix configuration
|
|
is modified.
|
|
|
|
The relevant nixos option is
|
|
`hardware.raspberry-pi.config`. Configuration is partitioned into
|
|
three sections:
|
|
|
|
1. Base device tree parameters `base-dt-params`
|
|
2. Device tree overlays `dt-overlays`
|
|
3. Firmware options `options`
|
|
|
|
Other than that, the format follows pretty closely to the config.txt
|
|
format. For example:
|
|
|
|
```nix
|
|
hardware.raspberry-pi.config = {
|
|
cm4 = {
|
|
options = {
|
|
otg_mode = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
};
|
|
};
|
|
pi4 = {
|
|
options = {
|
|
arm_boost = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
};
|
|
dt-overlays = {
|
|
vc4-kms-v3d = {
|
|
enable = true;
|
|
params = { cma-512 = { enable = true; }; };
|
|
};
|
|
};
|
|
};
|
|
all = {
|
|
options = {
|
|
# The firmware will start our u-boot binary rather than a
|
|
# linux kernel.
|
|
kernel = {
|
|
enable = true;
|
|
value = "u-boot-rpi-arm64.bin";
|
|
};
|
|
arm_64bit = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
enable_uart = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
avoid_warnings = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
camera_auto_detect = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
display_auto_detect = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
disable_overscan = {
|
|
enable = true;
|
|
value = true;
|
|
};
|
|
};
|
|
dt-overlays = {
|
|
vc4-kms-v3d = {
|
|
enable = true;
|
|
params = { };
|
|
};
|
|
};
|
|
base-dt-params = {
|
|
krnbt = {
|
|
enable = true;
|
|
value = "on";
|
|
};
|
|
spi = {
|
|
enable = true;
|
|
value = "on";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
```
|
|
|
|
generates the following config.txt:
|
|
|
|
```
|
|
# This is a generated file. Do not edit!
|
|
[all]
|
|
arm_64bit=1
|
|
avoid_warnings=1
|
|
camera_auto_detect=1
|
|
disable_overscan=1
|
|
display_auto_detect=1
|
|
enable_uart=1
|
|
kernel=u-boot-rpi-arm64.bin
|
|
dtparam=krnbt=on
|
|
dtparam=spi=on
|
|
dtoverlay=vc4-kms-v3d
|
|
|
|
dtoverlay=
|
|
|
|
[cm4]
|
|
otg_mode=1
|
|
|
|
[pi4]
|
|
arm_boost=1
|
|
dtoverlay=vc4-kms-v3d
|
|
dtparam=cma-512
|
|
dtoverlay=
|
|
```
|
|
|
|
If you want to preview the generated `config.txt`, you can find
|
|
it at the path `config.hardware.raspberry-pi.config-output`. For
|
|
example, if you had the above configuration then you could build the
|
|
`config.txt` file with:
|
|
|
|
```
|
|
nix build '.#nixosConfigurations.rpi-example.config.hardware.raspberry-pi.config-output'
|
|
```
|
|
|
|
## Firmware partition implementation notes
|
|
|
|
In Raspberry Pi devices the proprietary firmware manipulates the
|
|
device tree in a number of ways before handing it off to the kernel
|
|
(or in our case, to u-boot). The transformations that are performed
|
|
aren't documented so well (although I have found [this
|
|
list](https://forums.raspberrypi.com/viewtopic.php?t=329799#p1974233)
|
|
).
|
|
|
|
This manipulation makes it difficult to use the device tree configured
|
|
directly by NixOS as the proprietary firmware's manipulation must be
|
|
known and reproduced.
|
|
|
|
Even if the manipulation were successfully reproduced, some benefits
|
|
would be lost. For example, the firmware can detect connected hardware
|
|
during boot and automatically configure the device tree accordingly
|
|
before passing it onto the kernel. If this firmware device tree is
|
|
ignored then a NixOS system rebuild with a different device tree would
|
|
be required when swapping connected hardware. Examples of what I mean
|
|
by hardware include: the specific Raspberry Pi device booting the
|
|
image, connected cameras, and connected displays.
|
|
|
|
So, in order to avoid the headaches associated with failing to
|
|
reproduce some firmware device tree manipulation, and to reap the
|
|
benefits afforded by the firmware device tree configuration, u-boot is
|
|
configured to use the device tree that it is given (i.e. the one that
|
|
the raspberry pi firmware loads and manipulates). As a consequence,
|
|
device tree configuration is controlled via the [config.txt
|
|
file](https://www.raspberrypi.com/documentation/computers/config_txt.html).
|
|
|
|
Additionally, the firmware, device trees, and overlays from the
|
|
`raspberrypifw` package populate the firmware partition. This package
|
|
is kept up to date by the overlay applied by this package, so you
|
|
don't need configure this. However, if you want to use different
|
|
firmware you can override that package to do so.
|
|
|