Compare commits

..

No commits in common. "master" and "v0.3.0" have entirely different histories.

14 changed files with 387 additions and 539 deletions

View file

@ -1,23 +0,0 @@
name: update-flake-lock
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0'
permissions:
contents: write
pull-requests: write
jobs:
lockfile:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Install nix
uses: DeterminateSystems/nix-installer-action@e50d5f73bfe71c2dd0aa4218de8f4afa59f8f81d # v16
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@a2bbe0274e3a0c4194390a1e445f734c597ebc37 # v24

173
README.md
View file

@ -17,29 +17,96 @@ The important modules are `overlay/default.nix`, `rpi/default.nix`,
and `rpi/config.nix`. The other modules are mostly wrappers that set and `rpi/config.nix`. The other modules are mostly wrappers that set
`config.txt` settings and enable required kernel modules. `config.txt` settings and enable required kernel modules.
## Stability note
`master` is the development branch -- if you want to avoid breaking changes, you
should pin your flake to a specific release and refer to the release notes when
upgrading.
## Example ## Example
See the `rpi-example` config in this flake for an example config built by CI. 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 ## Using the provided cache to avoid compiling linux
This repo uses the raspberry pi linux kernel fork, and compiling linux takes a This repo uses the raspberry pi linux kernel fork, and compiling linux
while. CI pushes kernel builds to the nix-community cachix cache that you may takes a while. I do push my kernel builds to a cachix cache that you
use to avoid compiling linux yourself. The cache can be found at may use to avoid compiling linux yourself. The cache can be found
https://nix-community.cachix.org, and you can follow the instructions there at https://raspberry-pi-nix.cachix.org, and you can follow the
to use this cache. 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 ## Building an sd-card image
Include the provided `sd-image` nixos module this flake provides, then an image An image suitable for flashing to an sd-card can be found at the
suitable for flashing to an sd-card can be found at the attribute attribute `config.system.build.sdImage`. For example, if you wanted to
`config.system.build.sdImage`. For example, if you wanted to build an image for build an image for `rpi-example` in the above configuration
`rpi-example` in the above configuration example you could run: example you could run:
``` ```
nix build '.#nixosConfigurations.rpi-example.config.system.build.sdImage' nix build '.#nixosConfigurations.rpi-example.config.system.build.sdImage'
@ -47,15 +114,16 @@ nix build '.#nixosConfigurations.rpi-example.config.system.build.sdImage'
## The firmware partition ## The firmware partition
The image produced by this package is partitioned in the same way as the aarch64 The image produced by this package is partitioned in the same way as
installation media from nixpkgs: There is a firmware partition that contains the aarch64 installation media from nixpkgs: There is a firmware
necessary firmware, the kernel or u-boot, and config.txt. Then there is another partition that contains necessary firmware, u-boot, and
partition (labeled `NIXOS_SD`) that contains everything else. The firmware and config.txt. Then there is another partition (labeled `NIXOS_SD`) that
`config.txt` file are managed by NixOS modules defined in this contains everything else. The firmware and `config.txt` file are
package. Additionally, a systemd service will update the firmware and managed by NixOS modules defined in this package. Additionally, a
`config.txt` in the firmware partition __in place__. If uboot is enabled then systemd service will update the firmware and `config.txt` in the
linux kernels are stored in the `NIXOS_SD` partition and will be booted by firmware partition __in place__. Linux kernels are stored in the
u-boot in the firmware partition. `NIXOS_SD` partition and will be booted by u-boot in the firmware
partition.
## `config.txt` generation ## `config.txt` generation
@ -190,36 +258,37 @@ nix build '.#nixosConfigurations.rpi-example.config.hardware.raspberry-pi.config
## Firmware partition implementation notes ## Firmware partition implementation notes
In Raspberry Pi devices the proprietary firmware manipulates the device tree in In Raspberry Pi devices the proprietary firmware manipulates the
a number of ways before handing it off to the kernel (or in our case, to device tree in a number of ways before handing it off to the kernel
u-boot). The transformations that are performed aren't documented so well (or in our case, to u-boot). The transformations that are performed
(although I have found [this aren't documented so well (although I have found [this
list](https://forums.raspberrypi.com/viewtopic.php?t=329799#p1974233) ). list](https://forums.raspberrypi.com/viewtopic.php?t=329799#p1974233)
).
This manipulation makes it difficult to use the device tree configured directly This manipulation makes it difficult to use the device tree configured
by NixOS as the proprietary firmware's manipulation must be known and directly by NixOS as the proprietary firmware's manipulation must be
reproduced. known and reproduced.
Even if the manipulation were successfully reproduced, some benefits would be Even if the manipulation were successfully reproduced, some benefits
lost. For example, the firmware can detect connected hardware during boot and would be lost. For example, the firmware can detect connected hardware
automatically configure the device tree accordingly before passing it onto the during boot and automatically configure the device tree accordingly
kernel. If this firmware device tree is ignored then a NixOS system rebuild with before passing it onto the kernel. If this firmware device tree is
a different device tree would be required when swapping connected ignored then a NixOS system rebuild with a different device tree would
hardware. Examples of what I mean by hardware include: the specific Raspberry Pi be required when swapping connected hardware. Examples of what I mean
device booting the image, connected cameras, and connected displays. 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 So, in order to avoid the headaches associated with failing to
firmware device tree manipulation, and to reap the benefits afforded by the reproduce some firmware device tree manipulation, and to reap the
firmware device tree configuration, the bootloader is configured to use the benefits afforded by the firmware device tree configuration, u-boot is
device tree that it is given (i.e. the one that the raspberry pi firmware loads configured to use the device tree that it is given (i.e. the one that
and manipulates). As a consequence, device tree configuration is controlled via the raspberry pi firmware loads and manipulates). As a consequence,
the [config.txt device tree configuration is controlled via the [config.txt
file](https://www.raspberrypi.com/documentation/computers/config_txt.html). file](https://www.raspberrypi.com/documentation/computers/config_txt.html).
Additionally, the firmware, device trees, and overlays from the `raspberrypifw` Additionally, the firmware, device trees, and overlays from the
package populate the firmware partition. This package is kept up to date by the `raspberrypifw` package populate the firmware partition. This package
overlay applied by this package, so you don't need configure this. However, if is kept up to date by the overlay applied by this package, so you
you want to use different firmware you can override that package to do so. don't need configure this. However, if you want to use different
firmware you can override that package to do so.
## What's not working?
- [ ] Pi 5 u-boot devices other than sd-cards (i.e. usb, nvme).

View file

@ -1,44 +0,0 @@
{ pkgs, lib, ... }: {
time.timeZone = "America/New_York";
users.users.root.initialPassword = "root";
networking = {
hostName = "example";
useDHCP = false;
interfaces = {
wlan0.useDHCP = true;
eth0.useDHCP = true;
};
};
raspberry-pi-nix.board = "bcm2711";
hardware = {
raspberry-pi = {
config = {
all = {
base-dt-params = {
BOOT_UART = {
value = 1;
enable = true;
};
uart_2ndstage = {
value = 1;
enable = true;
};
};
dt-overlays = {
disable-bt = {
enable = true;
params = { };
};
};
};
};
};
};
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
};
}

134
flake.lock generated
View file

@ -1,186 +1,164 @@
{ {
"nodes": { "nodes": {
"libcamera-apps-src": {
"flake": false,
"locked": {
"lastModified": 1713431793,
"narHash": "sha256-uoewZMGf3vsBoRDfRz8KBKl+J6st/J44SHvNRMBdaUI=",
"owner": "raspberrypi",
"repo": "libcamera-apps",
"rev": "414a7383464b98f21f5e5381a16cc73ae0350ba6",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.4.4",
"repo": "libcamera-apps",
"type": "github"
}
},
"libcamera-src": { "libcamera-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1725630279, "lastModified": 1713446223,
"narHash": "sha256-KH30jmHfxXq4j2CL7kv18DYECJRp9ECuWNPnqPZajPA=", "narHash": "sha256-p0/inkHPRUkxSIsTmj7VI7sIaX7OXdqjMGZ31W7cnt4=",
"owner": "raspberrypi", "owner": "raspberrypi",
"repo": "libcamera", "repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db", "rev": "eb00c13d7c9f937732305d47af5b8ccf895e700f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "raspberrypi", "owner": "raspberrypi",
"repo": "libcamera", "repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db", "rev": "eb00c13d7c9f937732305d47af5b8ccf895e700f",
"type": "github" "type": "github"
} }
}, },
"libpisp-src": { "libpisp-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1724944683, "lastModified": 1713362873,
"narHash": "sha256-Fo2UJmQHS855YSSKKmGrsQnJzXog1cdpkIOO72yYAM4=", "narHash": "sha256-CHd44CH5dBcZuK+5fZtONZ8HE/lwGKwK5U0BYUK8gG4=",
"owner": "raspberrypi", "owner": "raspberrypi",
"repo": "libpisp", "repo": "libpisp",
"rev": "28196ed6edcfeda88d23cc5f213d51aa6fa17bb3", "rev": "999da5acb4f40cb8e93d22ec16e28edd55ec9414",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "raspberrypi", "owner": "raspberrypi",
"ref": "v1.0.7", "ref": "v1.0.5",
"repo": "libpisp", "repo": "libpisp",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1736061677, "lastModified": 1715218190,
"narHash": "sha256-DjkQPnkAfd7eB522PwnkGhOMuT9QVCZspDpJJYyOj60=", "narHash": "sha256-R98WOBHkk8wIi103JUVQF3ei3oui4HvoZcz9tYOAwlk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "cbd8ec4de4469333c82ff40d057350c30e9f7d36", "rev": "9a9960b98418f8c385f52de3b09a63f9c561427a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9a9960b98418f8c385f52de3b09a63f9c561427a",
"type": "github" "type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"libcamera-apps-src": "libcamera-apps-src",
"libcamera-src": "libcamera-src", "libcamera-src": "libcamera-src",
"libpisp-src": "libpisp-src", "libpisp-src": "libpisp-src",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"rpi-bluez-firmware-src": "rpi-bluez-firmware-src", "rpi-bluez-firmware-src": "rpi-bluez-firmware-src",
"rpi-firmware-nonfree-src": "rpi-firmware-nonfree-src", "rpi-firmware-nonfree-src": "rpi-firmware-nonfree-src",
"rpi-firmware-src": "rpi-firmware-src", "rpi-firmware-src": "rpi-firmware-src",
"rpi-linux-6_12_17-src": "rpi-linux-6_12_17-src", "rpi-linux-6_6-src": "rpi-linux-6_6-src",
"rpi-linux-6_6_78-src": "rpi-linux-6_6_78-src", "u-boot-src": "u-boot-src"
"rpi-linux-stable-src": "rpi-linux-stable-src",
"rpicam-apps-src": "rpicam-apps-src"
} }
}, },
"rpi-bluez-firmware-src": { "rpi-bluez-firmware-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1708969706, "lastModified": 1698157837,
"narHash": "sha256-KakKnOBeWxh0exu44beZ7cbr5ni4RA9vkWYb9sGMb8Q=", "narHash": "sha256-CjbZ3t3TW/iJ3+t9QKEtM9NdQU7SwcUCDYuTmFEwvhU=",
"owner": "RPi-Distro", "owner": "RPi-Distro",
"repo": "bluez-firmware", "repo": "bluez-firmware",
"rev": "78d6a07730e2d20c035899521ab67726dc028e1c", "rev": "d9d4741caba7314d6500f588b1eaa5ab387a4ff5",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "RPi-Distro", "owner": "RPi-Distro",
"ref": "bookworm",
"repo": "bluez-firmware", "repo": "bluez-firmware",
"rev": "d9d4741caba7314d6500f588b1eaa5ab387a4ff5",
"type": "github" "type": "github"
} }
}, },
"rpi-firmware-nonfree-src": { "rpi-firmware-nonfree-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1723266537, "lastModified": 1700058854,
"narHash": "sha256-T7eTKXqY9cxEMdab8Snda4CEOrEihy5uOhA6Fy+Mhnw=", "narHash": "sha256-Yynww79LPPkau4YDSLI6IMOjH64nMpHUdGjnCfIR2+M=",
"owner": "RPi-Distro", "owner": "RPi-Distro",
"repo": "firmware-nonfree", "repo": "firmware-nonfree",
"rev": "4b356e134e8333d073bd3802d767a825adec3807", "rev": "88aa085bfa1a4650e1ccd88896f8343c22a24055",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "RPi-Distro", "owner": "RPi-Distro",
"ref": "bookworm",
"repo": "firmware-nonfree", "repo": "firmware-nonfree",
"rev": "88aa085bfa1a4650e1ccd88896f8343c22a24055",
"type": "github" "type": "github"
} }
}, },
"rpi-firmware-src": { "rpi-firmware-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1728405098, "lastModified": 1713970515,
"narHash": "sha256-4gnK0KbqFnjBmWia9Jt2gveVWftmHrprpwBqYVqE/k0=", "narHash": "sha256-X5OinkLh/+mx34DM8mCk4tqOGuJdYxkvygv3gA77NJI=",
"owner": "raspberrypi", "owner": "raspberrypi",
"repo": "firmware", "repo": "firmware",
"rev": "7bbb5f80d20a2335066a8781459c9f33e5eebc64", "rev": "969420b4121b522ab33c5001074cc4c2547dafaf",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "raspberrypi", "owner": "raspberrypi",
"ref": "1.20241008", "ref": "1.20240424",
"repo": "firmware", "repo": "firmware",
"type": "github" "type": "github"
} }
}, },
"rpi-linux-6_12_17-src": { "rpi-linux-6_6-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1740765145, "lastModified": 1713516936,
"narHash": "sha256-hoCsGc4+RC/2LmxDtswLBL5ZhWlw4vSiL4Vkl39r2MU=", "narHash": "sha256-mlsDuVczu0e57BlD/iq7IEEluOIgqbZ+W4Ju30E/zhw=",
"owner": "raspberrypi", "owner": "raspberrypi",
"repo": "linux", "repo": "linux",
"rev": "5985ce32e511f4e8279a841a1b06a8c7d972b386", "rev": "0c341f47adc3578cd5f817aa20ee2b7f9ae6b23e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "raspberrypi", "owner": "raspberrypi",
"ref": "rpi-6.12.y", "ref": "stable_20240423",
"repo": "linux", "repo": "linux",
"type": "github" "type": "github"
} }
}, },
"rpi-linux-6_6_78-src": { "u-boot-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1740503700, "lastModified": 1712055538,
"narHash": "sha256-Y8+ot4Yi3UKwlZK3ap15rZZ16VZDvmeFkD46+6Ku7bE=", "narHash": "sha256-IlaDdjKq/Pq2orzcU959h93WXRZfvKBGDO/MFw9mZMg=",
"owner": "raspberrypi", "type": "tarball",
"repo": "linux", "url": "https://ftp.denx.de/pub/u-boot/u-boot-2024.04.tar.bz2"
"rev": "2e071057fded90e789c0101498e45a1778be93fe",
"type": "github"
}, },
"original": { "original": {
"owner": "raspberrypi", "type": "tarball",
"ref": "rpi-6.6.y", "url": "https://ftp.denx.de/pub/u-boot/u-boot-2024.04.tar.bz2"
"repo": "linux",
"type": "github"
}
},
"rpi-linux-stable-src": {
"flake": false,
"locked": {
"lastModified": 1728403745,
"narHash": "sha256-phCxkuO+jUGZkfzSrBq6yErQeO2Td+inIGHxctXbD5U=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "5aeecea9f4a45248bcf564dec924965e066a7bfd",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "stable_20241008",
"repo": "linux",
"type": "github"
}
},
"rpicam-apps-src": {
"flake": false,
"locked": {
"lastModified": 1727515047,
"narHash": "sha256-qCYGrcibOeGztxf+sd44lD6VAOGoUNwRqZDdAmcTa/U=",
"owner": "raspberrypi",
"repo": "rpicam-apps",
"rev": "a8ccf9f3cd9df49875dfb834a2b490d41d226031",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.5.2",
"repo": "rpicam-apps",
"type": "github"
} }
} }
}, },

View file

@ -2,42 +2,38 @@
description = "raspberry-pi nixos configuration"; description = "raspberry-pi nixos configuration";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; nixpkgs.url = "github:NixOS/nixpkgs/9a9960b98418f8c385f52de3b09a63f9c561427a";
rpi-linux-stable-src = { u-boot-src = {
flake = false; flake = false;
url = "github:raspberrypi/linux/stable_20241008"; url = "https://ftp.denx.de/pub/u-boot/u-boot-2024.04.tar.bz2";
}; };
rpi-linux-6_6_78-src = { rpi-linux-6_6-src = {
flake = false; flake = false;
url = "github:raspberrypi/linux/rpi-6.6.y"; url = "github:raspberrypi/linux/stable_20240423";
};
rpi-linux-6_12_17-src = {
flake = false;
url = "github:raspberrypi/linux/rpi-6.12.y";
}; };
rpi-firmware-src = { rpi-firmware-src = {
flake = false; flake = false;
url = "github:raspberrypi/firmware/1.20241008"; url = "github:raspberrypi/firmware/1.20240424";
}; };
rpi-firmware-nonfree-src = { rpi-firmware-nonfree-src = {
flake = false; flake = false;
url = "github:RPi-Distro/firmware-nonfree/bookworm"; url = "github:RPi-Distro/firmware-nonfree/88aa085bfa1a4650e1ccd88896f8343c22a24055";
}; };
rpi-bluez-firmware-src = { rpi-bluez-firmware-src = {
flake = false; flake = false;
url = "github:RPi-Distro/bluez-firmware/bookworm"; url = "github:RPi-Distro/bluez-firmware/d9d4741caba7314d6500f588b1eaa5ab387a4ff5";
}; };
rpicam-apps-src = { libcamera-apps-src = {
flake = false; flake = false;
url = "github:raspberrypi/rpicam-apps/v1.5.2"; url = "github:raspberrypi/libcamera-apps/v1.4.4";
}; };
libcamera-src = { libcamera-src = {
flake = false; flake = false;
url = "github:raspberrypi/libcamera/69a894c4adad524d3063dd027f5c4774485cf9db"; # v0.3.1+rpt20240906 url = "github:raspberrypi/libcamera/eb00c13d7c9f937732305d47af5b8ccf895e700f"; # v0.2.0+rpt20240418
}; };
libpisp-src = { libpisp-src = {
flake = false; flake = false;
url = "github:raspberrypi/libpisp/v1.0.7"; url = "github:raspberrypi/libpisp/v1.0.5";
}; };
}; };
@ -53,39 +49,13 @@
core = import ./overlays (builtins.removeAttrs srcs [ "self" ]); core = import ./overlays (builtins.removeAttrs srcs [ "self" ]);
libcamera = import ./overlays/libcamera.nix (builtins.removeAttrs srcs [ "self" ]); libcamera = import ./overlays/libcamera.nix (builtins.removeAttrs srcs [ "self" ]);
}; };
nixosModules = { nixosModules.raspberry-pi = import ./rpi {
raspberry-pi = import ./rpi { inherit pinned;
inherit pinned; core-overlay = self.overlays.core;
core-overlay = self.overlays.core; libcamera-overlay = self.overlays.libcamera;
libcamera-overlay = self.overlays.libcamera;
};
sd-image = import ./sd-image;
}; };
nixosConfigurations = { packages.aarch64-linux = {
rpi-example = srcs.nixpkgs.lib.nixosSystem { linux = pinned.rpi-kernels.latest.kernel;
system = "aarch64-linux";
modules = [ self.nixosModules.raspberry-pi self.nixosModules.sd-image ./example ];
};
}; };
checks.aarch64-linux = self.packages.aarch64-linux;
packages.aarch64-linux = with pinned.lib;
let
kernels =
foldlAttrs f { } pinned.rpi-kernels;
f = acc: kernel-version: board-attr-set:
foldlAttrs
(acc: board-version: drv: acc // {
"linux-${kernel-version}-${board-version}" = drv;
})
acc
board-attr-set;
in
{
example-sd-image = self.nixosConfigurations.rpi-example.config.system.build.sdImage;
firmware = pinned.raspberrypifw;
libcamera = pinned.libcamera;
wireless-firmware = pinned.raspberrypiWirelessFirmware;
uboot-rpi-arm64 = pinned.uboot-rpi-arm64;
} // kernels;
}; };
} }

View file

@ -1,6 +1,5 @@
{ rpi-linux-stable-src { u-boot-src
, rpi-linux-6_6_78-src , rpi-linux-6_6-src
, rpi-linux-6_12_17-src
, rpi-firmware-src , rpi-firmware-src
, rpi-firmware-nonfree-src , rpi-firmware-nonfree-src
, rpi-bluez-firmware-src , rpi-bluez-firmware-src
@ -8,85 +7,46 @@
}: }:
final: prev: final: prev:
let let
versions = { # The version to stick at `pkgs.rpi-kernels.latest'
v6_6_51.src = rpi-linux-stable-src; latest = "v6_6_28";
v6_6_78.src = rpi-linux-6_6_78-src;
v6_12_17 = {
src = rpi-linux-6_12_17-src;
patches = [
{
name = "remove-readme-target.patch";
patch = final.fetchpatch {
url = "https://github.com/raspberrypi/linux/commit/3c0fd51d184f1748b83d28e1113265425c19bcb5.patch";
hash = "sha256-v7uZOmPCUp2i7NGVgjqnQYe6dEBD+aATuP/oRs9jfuk=";
};
}
];
};
};
boards = [ "bcm2711" "bcm2712" ];
# Helpers for building the `pkgs.rpi-kernels' map. # Helpers for building the `pkgs.rpi-kernels' map.
rpi-kernel = { version, board }: rpi-kernel = { kernel, version, fw, wireless-fw, argsOverride ? null }:
let let
kernel = builtins.getAttr version versions; new-kernel = prev.linux_rpi4.override {
version-slug = builtins.replaceStrings [ "v" "_" ] [ "" "." ] version; argsOverride = {
src = kernel;
inherit version;
modDirVersion = version;
} // (if builtins.isNull argsOverride then { } else argsOverride);
};
new-fw = prev.raspberrypifw.overrideAttrs (oldfw: { src = fw; });
new-wireless-fw = final.callPackage wireless-fw { };
version-slug = builtins.replaceStrings [ "." ] [ "_" ] version;
in in
{ {
"${version}"."${board}" = (final.buildLinux { "v${version-slug}" = {
modDirVersion = version-slug; kernel = new-kernel;
version = version-slug; firmware = new-fw;
pname = "linux-rpi"; wireless-firmware = new-wireless-fw;
src = kernel.src; };
defconfig = "${board}_defconfig";
structuredExtraConfig = with final.lib.kernel; {
# The perl script to generate kernel options sets unspecified
# parameters to `m` if possible [1]. This results in the
# unspecified config option KUNIT [2] getting set to `m` which
# causes DRM_VC4_KUNIT_TEST [3] to get set to `y`.
#
# This vc4 unit test fails on boot due to a null pointer
# exception with the existing config. I'm not sure why, but in
# any case, the DRM_VC4_KUNIT_TEST config option itself states
# that it is only useful for kernel developers working on the
# vc4 driver. So, I feel no need to deviate from the standard
# rpi kernel and attempt to successfully enable this test and
# other unit tests because the nixos perl script has this
# sloppy "default to m" behavior. So, I set KUNIT to `n`.
#
# [1] https://github.com/NixOS/nixpkgs/blob/85bcb95aa83be667e562e781e9d186c57a07d757/pkgs/os-specific/linux/kernel/generate-config.pl#L1-L10
# [2] https://github.com/raspberrypi/linux/blob/1.20230405/lib/kunit/Kconfig#L5-L14
# [3] https://github.com/raspberrypi/linux/blob/bb63dc31e48948bc2649357758c7a152210109c4/drivers/gpu/drm/vc4/Kconfig#L38-L52
KUNIT = no;
};
features.efiBootStub = false;
kernelPatches =
if kernel ? "patches" then kernel.patches else [ ];
ignoreConfigErrors = true;
}).overrideAttrs
(oldAttrs: {
postConfigure = ''
# The v7 defconfig has this set to '-v7' which screws up our modDirVersion.
sed -i $buildRoot/.config -e 's/^CONFIG_LOCALVERSION=.*/CONFIG_LOCALVERSION=""/'
sed -i $buildRoot/include/config/auto.conf -e 's/^CONFIG_LOCALVERSION=.*/CONFIG_LOCALVERSION=""/'
'';
});
}; };
rpi-kernels = builtins.foldl' rpi-kernels = builtins.foldl' (b: a: b // rpi-kernel a) { };
(b: a: final.lib.recursiveUpdate b (rpi-kernel a))
{ };
in in
{ {
# disable firmware compression so that brcm firmware can be found at # disable firmware compression so that brcm firmware can be found at
# the path expected by raspberry pi firmware/device tree # the path expected by raspberry pi firmware/device tree
compressFirmwareXz = x: x; compressFirmwareXz = x: x;
compressFirmwareZstd = x: x;
# provide generic rpi arm64 u-boot # provide generic rpi arm64 u-boot
uboot-rpi-arm64 = final.buildUBoot { uboot_rpi_arm64 = prev.buildUBoot rec {
defconfig = "rpi_arm64_defconfig"; defconfig = "rpi_arm64_defconfig";
extraMeta.platforms = [ "aarch64-linux" ]; extraMeta.platforms = [ "aarch64-linux" ];
filesToInstall = [ "u-boot.bin" ]; filesToInstall = [ "u-boot.bin" ];
version = "2024.04";
patches = [ ];
makeFlags = [ ];
src = u-boot-src;
# In raspberry pi sbcs the firmware manipulates the device tree in # In raspberry pi sbcs the firmware manipulates the device tree in
# a variety of ways before handing it off to the linux kernel. [1] # a variety of ways before handing it off to the linux kernel. [1]
# Since we have installed u-boot in place of a linux kernel we may # Since we have installed u-boot in place of a linux kernel we may
@ -100,23 +60,46 @@ in
}; };
# default to latest firmware # default to latest firmware
raspberrypiWirelessFirmware = final.callPackage raspberrypiWirelessFirmware = final.rpi-kernels.latest.wireless-firmware;
( raspberrypifw = final.rpi-kernels.latest.firmware;
import ./raspberrypi-wireless-firmware.nix {
bluez-firmware = rpi-bluez-firmware-src;
firmware-nonfree = rpi-firmware-nonfree-src;
}
)
{ };
raspberrypifw = prev.raspberrypifw.overrideAttrs (oldfw: { src = rpi-firmware-src; });
} // { } // {
# rpi kernels and firmware are available at # rpi kernels and firmware are available at
# `pkgs.rpi-kernels.<VERSION>.<BOARD>'. # `pkgs.rpi-kernels.<VERSION>.{kernel,firmware,wireless-firmware}'.
# #
# For example: `pkgs.rpi-kernels.v6_6_78.bcm2712' # For example: `pkgs.rpi-kernels.v5_15_87.kernel'
rpi-kernels = rpi-kernels ( rpi-kernels = rpi-kernels [{
final.lib.cartesianProduct version = "6.6.28";
{ board = boards; version = (builtins.attrNames versions); } kernel = rpi-linux-6_6-src;
); fw = rpi-firmware-src;
wireless-fw = import ./raspberrypi-wireless-firmware.nix {
bluez-firmware = rpi-bluez-firmware-src;
firmware-nonfree = rpi-firmware-nonfree-src;
};
argsOverride = {
structuredExtraConfig = with prev.lib.kernel; {
# The perl script to generate kernel options sets unspecified
# parameters to `m` if possible [1]. This results in the
# unspecified config option KUNIT [2] getting set to `m` which
# causes DRM_VC4_KUNIT_TEST [3] to get set to `y`.
#
# This vc4 unit test fails on boot due to a null pointer
# exception with the existing config. I'm not sure why, but in
# any case, the DRM_VC4_KUNIT_TEST config option itself states
# that it is only useful for kernel developers working on the
# vc4 driver. So, I feel no need to deviate from the standard
# rpi kernel and attempt to successfully enable this test and
# other unit tests because the nixos perl script has this
# sloppy "default to m" behavior. So, I set KUNIT to `n`.
#
# [1] https://github.com/NixOS/nixpkgs/blob/85bcb95aa83be667e562e781e9d186c57a07d757/pkgs/os-specific/linux/kernel/generate-config.pl#L1-L10
# [2] https://github.com/raspberrypi/linux/blob/1.20230405/lib/kunit/Kconfig#L5-L14
# [3] https://github.com/raspberrypi/linux/blob/bb63dc31e48948bc2649357758c7a152210109c4/drivers/gpu/drm/vc4/Kconfig#L38-L52
KUNIT = no;
GPIO_PWM = no;
};
};
}] // {
latest = final.rpi-kernels."${latest}";
};
} }

View file

@ -0,0 +1,43 @@
{ libcamera-apps-src
, lib
, stdenv
, fetchFromGitHub
, fetchpatch
, meson
, pkg-config
, libjpeg
, libtiff
, libpng
, libcamera
, libepoxy
, boost
, libexif
, ninja
}:
stdenv.mkDerivation rec {
pname = "libcamera-apps";
version = "v1.4.1";
src = libcamera-apps-src;
nativeBuildInputs = [ meson pkg-config ];
buildInputs = [ libjpeg libtiff libcamera libepoxy boost libexif libpng ninja ];
mesonFlags = [
"-Denable_qt=false"
"-Denable_opencv=false"
"-Denable_tflite=false"
"-Denable_drm=true"
];
# Meson is no longer able to pick up Boost automatically.
# https://github.com/NixOS/nixpkgs/issues/86131
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
meta = with lib; {
description = "Userland tools interfacing with Raspberry Pi cameras";
homepage = "https://github.com/raspberrypi/libcamera-apps";
license = licenses.bsd2;
platforms = [ "aarch64-linux" ];
};
}

View file

@ -1,16 +1,17 @@
{ rpicam-apps-src { libcamera-apps-src
, libcamera-src , libcamera-src
, libpisp-src , libpisp-src
, ... , ...
}: }:
final: prev: { final: prev:
# A recent known working version of rpicam-apps {
# A recent known working version of libcamera-apps
libcamera-apps = libcamera-apps =
final.callPackage ./rpicam-apps.nix { inherit rpicam-apps-src; }; final.callPackage ./libcamera-apps.nix { inherit libcamera-apps-src; };
libpisp = final.stdenv.mkDerivation { libpisp = final.stdenv.mkDerivation {
name = "libpisp"; name = "libpisp";
version = "1.0.7"; version = "1.0.3";
src = libpisp-src; src = libpisp-src;
nativeBuildInputs = with final; [ pkg-config meson ninja ]; nativeBuildInputs = with final; [ pkg-config meson ninja ];
buildInputs = with final; [ nlohmann_json boost ]; buildInputs = with final; [ nlohmann_json boost ];
@ -21,37 +22,9 @@ final: prev: {
}; };
libcamera = prev.libcamera.overrideAttrs (old: { libcamera = prev.libcamera.overrideAttrs (old: {
version = "0.3.1"; version = "0.1.0";
src = libcamera-src; src = libcamera-src;
buildInputs = old.buildInputs ++ (with final; [ buildInputs = old.buildInputs ++ (with final; [ libpisp ]);
libpisp
openssl
libtiff
(python3.withPackages (ps: with ps; [
python3-gnutls
pybind11
pyyaml
ply
]))
libglibutil
gst_all_1.gst-plugins-base
]);
patches = [ ]; patches = [ ];
postPatch = ''
patchShebangs src/py/ utils/
'';
mesonFlags = [
"--buildtype=release"
"-Dpipelines=rpi/vc4,rpi/pisp"
"-Dipas=rpi/vc4,rpi/pisp"
"-Dv4l2=true"
"-Dgstreamer=enabled"
"-Dtest=false"
"-Dlc-compliance=disabled"
"-Dcam=disabled"
"-Dqcam=disabled"
"-Ddocumentation=enabled"
"-Dpycamera=enabled"
];
}); });
} }

View file

@ -1,9 +1,9 @@
{ bluez-firmware, firmware-nonfree }: { bluez-firmware, firmware-nonfree }:
{ lib, stdenvNoCC }: { lib, stdenvNoCC, fetchFromGitHub }:
stdenvNoCC.mkDerivation { stdenvNoCC.mkDerivation {
pname = "raspberrypi-wireless-firmware"; pname = "raspberrypi-wireless-firmware";
version = "2024-02-26"; version = "2023-11-15";
srcs = [ ]; srcs = [ ];

View file

@ -1,30 +0,0 @@
{ rpicam-apps-src, lib, pkgs, stdenv }:
stdenv.mkDerivation {
pname = "libcamera-apps";
version = "v1.5.0";
src = rpicam-apps-src;
nativeBuildInputs = with pkgs; [ meson pkg-config ];
buildInputs = with pkgs; [ libjpeg libtiff libcamera libepoxy boost libexif libpng ffmpeg libdrm ninja ];
mesonFlags = [
"-Denable_qt=disabled"
"-Denable_opencv=disabled"
"-Denable_tflite=disabled"
"-Denable_egl=disabled"
"-Denable_hailo=disabled"
"-Denable_drm=enabled"
];
# Meson is no longer able to pick up Boost automatically.
# https://github.com/NixOS/nixpkgs/issues/86131
BOOST_INCLUDEDIR = "${lib.getDev pkgs.boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib pkgs.boost}/lib";
meta = with lib; {
description = "Userland tools interfacing with Raspberry Pi cameras";
homepage = "https://github.com/raspberrypi/libcamera-apps";
license = licenses.bsd2;
platforms = [ "aarch64-linux" ];
};
}

View file

@ -93,7 +93,7 @@ in
}; };
}; };
base-dt-params = lib.mkOption { base-dt-params = lib.mkOption {
type = with lib.types; attrsOf (submodule dt-param); type = with lib.types; attrsOf (submodule rpi-config-param);
default = { }; default = { };
example = { example = {
i2c = { i2c = {

View file

@ -1,37 +1,14 @@
{ pinned, core-overlay, libcamera-overlay }: { pinned, core-overlay, libcamera-overlay }:
{ lib, pkgs, config, ... }: { lib, pkgs, config, ... }:
let let cfg = config.raspberry-pi-nix;
cfg = config.raspberry-pi-nix;
version = cfg.kernel-version;
board = cfg.board;
kernel = config.system.build.kernel;
initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
in in
{ {
imports = [ ./config.nix ./i2c.nix ]; imports = [ ../sd-image ./config.nix ./i2c.nix ];
options = with lib; { options = with lib; {
raspberry-pi-nix = { raspberry-pi-nix = {
kernel-version = mkOption { pin-kernel = {
default = "v6_6_51";
type = types.str;
description = "Kernel version to build.";
};
board = mkOption {
type = types.enum [ "bcm2711" "bcm2712" ];
description = ''
The kernel board version to build.
Examples at: https://www.raspberrypi.com/documentation/computers/linux_kernel.html#native-build-configuration
without the _defconfig part.
'';
};
firmware-partition-label = mkOption {
default = "FIRMWARE";
type = types.str;
description = "label of rpi firmware partition";
};
pin-inputs = {
enable = mkOption { enable = mkOption {
default = true; default = true;
type = types.bool; type = types.bool;
@ -61,7 +38,7 @@ in
}; };
uboot = { uboot = {
enable = mkOption { enable = mkOption {
default = false; default = true;
type = types.bool; type = types.bool;
description = '' description = ''
If enabled then uboot is used as the bootloader. If disabled If enabled then uboot is used as the bootloader. If disabled
@ -74,25 +51,24 @@ in
cm4 with an nvme drive. cm4 with an nvme drive.
''; '';
}; };
package = mkPackageOption pkgs "uboot-rpi-arm64" { };
};
serial-console = {
enable = mkOption {
default = true;
type = types.bool;
description = ''
Whether to enable a console on serial0.
Corresponds with raspi-config's setting
"Would you like a login shell to be accessible over serial?"
'';
};
}; };
}; };
}; };
config = { config = {
boot.kernelParams =
if cfg.uboot.enable then [ ]
else [
# This is ugly and fragile, but the sdImage image has an msdos
# table, so the partition table id is a 1-indexed hex
# number. So, we drop the hex prefix and stick on a "02" to
# refer to the root partition.
"root=PARTUUID=${lib.strings.removePrefix "0x" config.sdImage.firmwarePartitionID}-02"
"rootfstype=ext4"
"fsck.repair=yes"
"rootwait"
"init=/sbin/init"
];
systemd.services = { systemd.services = {
"raspberry-pi-firmware-migrate" = "raspberry-pi-firmware-migrate" =
{ {
@ -111,7 +87,7 @@ in
{ {
Type = "oneshot"; Type = "oneshot";
MountImages = MountImages =
"/dev/disk/by-label/${cfg.firmware-partition-label}:${firmware-path}"; "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}:${firmware-path}";
StateDirectory = "raspberrypi-firmware"; StateDirectory = "raspberrypi-firmware";
ExecStart = pkgs.writeShellScript "migrate-rpi-firmware" '' ExecStart = pkgs.writeShellScript "migrate-rpi-firmware" ''
shopt -s nullglob shopt -s nullglob
@ -119,7 +95,8 @@ in
TARGET_FIRMWARE_DIR="${firmware-path}" TARGET_FIRMWARE_DIR="${firmware-path}"
TARGET_OVERLAYS_DIR="$TARGET_FIRMWARE_DIR/overlays" TARGET_OVERLAYS_DIR="$TARGET_FIRMWARE_DIR/overlays"
TMPFILE="$TARGET_FIRMWARE_DIR/tmp" TMPFILE="$TARGET_FIRMWARE_DIR/tmp"
KERNEL="${kernel}/${config.system.boot.loader.kernelFile}" UBOOT="${pkgs.uboot_rpi_arm64}/u-boot.bin"
KERNEL="${pkgs.rpi-kernels.latest.kernel}/Image"
SHOULD_UBOOT=${if cfg.uboot.enable then "1" else "0"} SHOULD_UBOOT=${if cfg.uboot.enable then "1" else "0"}
SRC_FIRMWARE_DIR="${pkgs.raspberrypifw}/share/raspberrypi/boot" SRC_FIRMWARE_DIR="${pkgs.raspberrypifw}/share/raspberrypi/boot"
STARTFILES=("$SRC_FIRMWARE_DIR"/start*.elf) STARTFILES=("$SRC_FIRMWARE_DIR"/start*.elf)
@ -130,28 +107,24 @@ in
SRC_OVERLAYS=("$SRC_OVERLAYS_DIR"/*) SRC_OVERLAYS=("$SRC_OVERLAYS_DIR"/*)
CONFIG="${config.hardware.raspberry-pi.config-output}" CONFIG="${config.hardware.raspberry-pi.config-output}"
${lib.strings.optionalString cfg.uboot.enable '' migrate_uboot() {
UBOOT="${cfg.uboot.package}/u-boot.bin" echo "migrating uboot"
touch "$STATE_DIRECTORY/uboot-migration-in-progress"
migrate_uboot() { cp "$UBOOT" "$TMPFILE"
echo "migrating uboot" mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/u-boot-rpi-arm64.bin"
touch "$STATE_DIRECTORY/uboot-migration-in-progress" echo "${
cp "$UBOOT" "$TMPFILE" builtins.toString pkgs.uboot_rpi_arm64
mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/u-boot-rpi-arm64.bin" }" > "$STATE_DIRECTORY/uboot-version"
echo "${builtins.toString cfg.uboot.package}" > "$STATE_DIRECTORY/uboot-version" rm "$STATE_DIRECTORY/uboot-migration-in-progress"
rm "$STATE_DIRECTORY/uboot-migration-in-progress" }
}
''}
migrate_kernel() { migrate_kernel() {
echo "migrating kernel" echo "migrating kernel"
touch "$STATE_DIRECTORY/kernel-migration-in-progress" touch "$STATE_DIRECTORY/kernel-migration-in-progress"
cp "$KERNEL" "$TMPFILE" cp "$KERNEL" "$TMPFILE"
mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/kernel.img" mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/kernel.img"
cp "${initrd}" "$TMPFILE"
mv -T "$TMPFILE" "$TARGET_FIRMWARE_DIR/initrd"
echo "${ echo "${
builtins.toString kernel builtins.toString pkgs.rpi-kernels.latest.kernel
}" > "$STATE_DIRECTORY/kernel-version" }" > "$STATE_DIRECTORY/kernel-version"
rm "$STATE_DIRECTORY/kernel-migration-in-progress" rm "$STATE_DIRECTORY/kernel-migration-in-progress"
} }
@ -200,16 +173,14 @@ in
rm "$STATE_DIRECTORY/firmware-migration-in-progress" rm "$STATE_DIRECTORY/firmware-migration-in-progress"
} }
${lib.strings.optionalString cfg.uboot.enable '' if [[ "$SHOULD_UBOOT" -eq 1 ]] && [[ -f "$STATE_DIRECTORY/uboot-migration-in-progress" || ! -f "$STATE_DIRECTORY/uboot-version" || $(< "$STATE_DIRECTORY/uboot-version") != ${
if [[ "$SHOULD_UBOOT" -eq 1 ]] && [[ -f "$STATE_DIRECTORY/uboot-migration-in-progress" || ! -f "$STATE_DIRECTORY/uboot-version" || $(< "$STATE_DIRECTORY/uboot-version") != ${ builtins.toString pkgs.uboot_rpi_arm64
builtins.toString cfg.uboot.package } ]]; then
} ]]; then migrate_uboot
migrate_uboot fi
fi
''}
if [[ "$SHOULD_UBOOT" -ne 1 ]] && [[ ! -f "$STATE_DIRECTORY/kernel-version" || $(< "$STATE_DIRECTORY/kernel-version") != ${ if [[ "$SHOULD_UBOOT" -ne 1 ]] && [[ ! -f "$STATE_DIRECTORY/kernel-version" || $(< "$STATE_DIRECTORY/kernel-version") != ${
builtins.toString kernel builtins.toString pkgs.rpi-kernels.latest.kernel
} ]]; then } ]]; then
migrate_kernel migrate_kernel
fi fi
@ -263,14 +234,6 @@ in
enable = true; enable = true;
value = if cfg.uboot.enable then "u-boot-rpi-arm64.bin" else "kernel.img"; value = if cfg.uboot.enable then "u-boot-rpi-arm64.bin" else "kernel.img";
}; };
ramfsfile = {
enable = !cfg.uboot.enable;
value = "initrd";
};
ramfsaddr = {
enable = !cfg.uboot.enable;
value = -1;
};
arm_64bit = { arm_64bit = {
enable = true; enable = true;
value = true; value = true;
@ -306,50 +269,26 @@ in
}; };
nixpkgs = { nixpkgs = {
overlays = overlays = [ core-overlay ]
let ++ (if config.raspberry-pi-nix.libcamera-overlay.enable
rpi-overlays = [ core-overlay ] then [ libcamera-overlay ] else [ ]);
++ (if config.raspberry-pi-nix.libcamera-overlay.enable
then [ libcamera-overlay ] else [ ]);
rpi-overlay = lib.composeManyExtensions rpi-overlays;
pin-prev-overlay = overlay: pinned-prev: final: prev:
let
# apply the overlay to pinned-prev and fix that so no references to the actual final
# and prev appear in applied-overlay
applied-overlay =
lib.fix (final: pinned-prev // overlay final pinned-prev);
# We only want to set keys that appear in the overlay, so restrict applied-overlay to
# these keys
restricted-overlay = lib.getAttrs (builtins.attrNames (overlay { } { })) applied-overlay;
in
prev // restricted-overlay;
in
if cfg.pin-inputs.enable
then [ (pin-prev-overlay rpi-overlay pinned) ]
else [ rpi-overlay ];
}; };
boot = { boot = {
kernelParams = initrd.availableKernelModules = [
if cfg.uboot.enable then [ ] "usbhid"
else builtins.concatLists [ "usb_storage"
[ "console=tty1" ] "vc4"
(if cfg.serial-console.enable then [ "pcie_brcmstb" # required for the pcie bus to work
# https://github.com/raspberrypi/firmware/issues/1539#issuecomment-784498108 "reset-raspberrypi" # required for vl805 firmware to load
"console=serial0,115200n8" ];
] else [ ] # This pin is not necessary, it would be fine to replace it with
) # `pkgs.rpi-kernels.latest.kernel`. It is helpful to ensure
[ "init=/sbin/init" ] # cache hits for kernel builds though.
]; kernelPackages =
initrd = { if cfg.pin-kernel.enable
availableKernelModules = [ then pinned.linuxPackagesFor (pinned.rpi-kernels.latest.kernel)
"usbhid" else pkgs.linuxPackagesFor (pkgs.rpi-kernels.latest.kernel);
"usb_storage"
"vc4"
"pcie_brcmstb" # required for the pcie bus to work
"reset-raspberrypi" # required for vl805 firmware to load
];
};
kernelPackages = pkgs.linuxPackagesFor pkgs.rpi-kernels."${version}"."${board}";
loader = { loader = {
grub.enable = lib.mkDefault false; grub.enable = lib.mkDefault false;
initScript.enable = !cfg.uboot.enable; initScript.enable = !cfg.uboot.enable;
@ -363,8 +302,6 @@ in
}; };
hardware.enableRedistributableFirmware = true; hardware.enableRedistributableFirmware = true;
users.groups = builtins.listToAttrs (map (k: { name = k; value = { }; })
[ "input" "sudo" "plugdev" "games" "netdev" "gpio" "i2c" "spi" ]);
services = { services = {
udev.extraRules = udev.extraRules =
let shell = "${pkgs.bash}/bin/bash"; let shell = "${pkgs.bash}/bin/bash";

View file

@ -8,16 +8,8 @@
boot.consoleLogLevel = lib.mkDefault 7; boot.consoleLogLevel = lib.mkDefault 7;
boot.kernelParams = [ # https://github.com/raspberrypi/firmware/issues/1539#issuecomment-784498108
# This is ugly and fragile, but the sdImage image has an msdos boot.kernelParams = [ "console=serial0,115200n8" "console=tty1" ];
# table, so the partition table id is a 1-indexed hex
# number. So, we drop the hex prefix and stick on a "02" to
# refer to the root partition.
"root=PARTUUID=${lib.strings.removePrefix "0x" config.sdImage.firmwarePartitionID}-02"
"rootfstype=ext4"
"fsck.repair=yes"
"rootwait"
];
sdImage = sdImage =
let let
@ -27,19 +19,13 @@
${lib.strings.concatStringsSep " " config.boot.kernelParams} ${lib.strings.concatStringsSep " " config.boot.kernelParams}
''; '';
}; };
cfg = config.raspberry-pi-nix;
version = cfg.kernel-version;
board = cfg.board;
kernel = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}";
initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
populate-kernel = populate-kernel =
if cfg.uboot.enable if config.raspberry-pi-nix.uboot.enable
then '' then ''
cp ${cfg.uboot.package}/u-boot.bin firmware/u-boot-rpi-arm64.bin cp ${pkgs.uboot_rpi_arm64}/u-boot.bin firmware/u-boot-rpi-arm64.bin
'' ''
else '' else ''
cp "${kernel}" firmware/kernel.img cp "${pkgs.rpi-kernels.latest.kernel}/Image" firmware/kernel.img
cp "${initrd}" firmware/initrd
cp "${kernel-params}" firmware/cmdline.txt cp "${kernel-params}" firmware/cmdline.txt
''; '';
in in
@ -50,7 +36,7 @@
cp ${config.hardware.raspberry-pi.config-output} firmware/config.txt cp ${config.hardware.raspberry-pi.config-output} firmware/config.txt
''; '';
populateRootCommands = populateRootCommands =
if cfg.uboot.enable if config.raspberry-pi-nix.uboot.enable
then '' then ''
mkdir -p ./files/boot mkdir -p ./files/boot
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot

View file

@ -30,8 +30,7 @@ let
} // optionalAttrs (config.sdImage.rootPartitionUUID != null) { } // optionalAttrs (config.sdImage.rootPartitionUUID != null) {
uuid = config.sdImage.rootPartitionUUID; uuid = config.sdImage.rootPartitionUUID;
}); });
in in {
{
imports = [ ]; imports = [ ];
options.sdImage = { options.sdImage = {
@ -83,6 +82,14 @@ in
''; '';
}; };
firmwarePartitionName = mkOption {
type = types.str;
default = "FIRMWARE";
description = ''
Name of the filesystem which holds the boot firmware.
'';
};
rootPartitionUUID = mkOption { rootPartitionUUID = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
@ -153,7 +160,7 @@ in
config = { config = {
fileSystems = { fileSystems = {
"/boot/firmware" = { "/boot/firmware" = {
device = "/dev/disk/by-label/${config.raspberry-pi-nix.firmware-partition-label}"; device = "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}";
fsType = "vfat"; fsType = "vfat";
}; };
"/" = { "/" = {
@ -219,7 +226,7 @@ in
# Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img # Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img
eval $(partx $img -o START,SECTORS --nr 1 --pairs) eval $(partx $img -o START,SECTORS --nr 1 --pairs)
truncate -s $((SECTORS * 512)) firmware_part.img truncate -s $((SECTORS * 512)) firmware_part.img
faketime "1970-01-01 00:00:00" mkfs.vfat -i ${config.sdImage.firmwarePartitionID} -n ${config.raspberry-pi-nix.firmware-partition-label} firmware_part.img faketime "1970-01-01 00:00:00" mkfs.vfat -i ${config.sdImage.firmwarePartitionID} -n ${config.sdImage.firmwarePartitionName} firmware_part.img
# Populate the files intended for /boot/firmware # Populate the files intended for /boot/firmware
mkdir firmware mkdir firmware
@ -237,8 +244,7 @@ in
zstd -T$NIX_BUILD_CORES --rm $img zstd -T$NIX_BUILD_CORES --rm $img
fi fi
''; '';
}) }) { };
{ };
boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot '' boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot ''
# On the first boot do some maintenance tasks # On the first boot do some maintenance tasks
@ -248,7 +254,7 @@ in
# Figure out device names for the boot device and root filesystem. # Figure out device names for the boot device and root filesystem.
rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /) rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /)
bootDevice=$(lsblk -npo PKNAME $rootPart) bootDevice=$(lsblk -npo PKNAME $rootPart)
partNum=$(lsblk -npo PARTN $rootPart) partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
# Resize the root partition and the filesystem to fit the disk # Resize the root partition and the filesystem to fit the disk
echo ",+," | sfdisk -N$partNum --no-reread $bootDevice echo ",+," | sfdisk -N$partNum --no-reread $bootDevice