turny: fix SPI/GPIO config for newer kernels
Build Images / build (push) Successful in 1m36s
Check / check (push) Failing after 2m58s

- Add complete config.txt settings with u-boot boot lines + spi=on
- Override sdImage.populateFirmwareCommands to use configtxt module output
- Mount firmware partition and add activation script to sync config.txt
- Load spi_bcm2835 and bcm2835_gpiomem kernel modules
- Add udev rule for gpiomem subsystem (not just gpio)
- Relax ProtectKernelTunables so service can access GPIO
- Update turny flake input to rppal-based CS pin fix
This commit is contained in:
Joakim Repomaa
2026-07-05 12:21:03 +03:00
parent 0e664c51f5
commit e5af610f23
65 changed files with 1336 additions and 500 deletions
+152 -5
View File
@@ -4,6 +4,7 @@
{
pkgs,
lib,
ssh,
config,
inputs,
@@ -57,10 +58,10 @@ in
# Select internationalisation properties.
i18n.defaultLocale = "en_US.UTF-8";
# Define a user account. Don't forget to set a password with passwd.
# Define a user account. Don't forget to set a password with 'passwd'.
users.users.jokke = {
isNormalUser = true;
extraGroups = [ "wheel" ]; # Enable sudo for the user.
extraGroups = [ "wheel" ]; # Enable 'sudo' for the user.
packages = [ pkgs.nh ];
openssh.authorizedKeys.keys = [ ssh.publicKeys.yubikey ];
initialPassword = "changeme";
@@ -74,7 +75,7 @@ in
wget
htop
git
inputs.turny.packages.${stdenv.hostPlatform.system}.default
alsa-utils
];
# Enable the OpenSSH daemon.
@@ -88,11 +89,157 @@ in
allInterfaces = [ "ssh" ];
};
# Enable audio (ALSA)
hardware.alsa.enable = true;
# Complete config.txt settings: boot-critical u-boot lines plus SPI enable.
# The configtxt module generates the full config.txt, overriding the
# hardcoded one in sd-image-aarch64.nix which ignores these settings.
hardware.raspberry-pi.configtxt.settings = {
pi3 = {
kernel = "u-boot-rpi3.bin";
core_freq = 250;
};
pi02 = {
kernel = "u-boot-rpi3.bin";
};
pi4 = {
kernel = "u-boot-rpi4.bin";
enable_gic = true;
armstub = "armstub8-gic.bin";
};
all = {
arm_64bit = true;
enable_uart = true;
avoid_warnings = true;
dtparam = [
"audio=on"
"spi=on"
];
};
};
# Use the configtxt module's generated config.txt when building SD images
sdImage.populateFirmwareCommands = let
inherit (config.hardware.raspberry-pi.configtxt) file;
in ''
(cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/)
cp ${file} firmware/config.txt
cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-2-b.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-3-b.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-3-b-plus.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-cm3.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-zero-2.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-zero-2-w.dtb firmware/
cp ${pkgs.ubootRaspberryPi4_64bit}/u-boot.bin firmware/u-boot-rpi4.bin
cp ${pkgs.raspberrypi-armstubs}/armstub8-gic.bin firmware/armstub8-gic.bin
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-4-b.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-400.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-cm4.dtb firmware/
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-cm4s.dtb firmware/
'';
# Load SPI and GPIO kernel modules so /dev/spidev* and /dev/gpiomem exist
boot.kernelModules = [
"spi_bcm2835"
"bcm2835_gpiomem"
];
# Use the firmware-passed device tree (with dtparam/dtoverlay applied)
# instead of u-boot loading a fresh DTB from FDTDIR
boot.loader.generic-extlinux-compatible.useGenerationDeviceTree = false;
# Mount the firmware partition so config.txt is accessible and can be
# updated on deploys. The sd-image module defaults to noauto; we need it
# mounted so the activation script can sync config.txt.
fileSystems."/boot/firmware".options = [
"nofail"
"defaults"
];
# Sync the generated config.txt to the firmware partition on each deploy
# so dtparam/dtoverlay changes take effect without reflashing the SD card.
system.activationScripts.syncConfigTxt = {
text = ''
if mountpoint -q /boot/firmware; then
cp -f ${config.hardware.raspberry-pi.configtxt.file} /boot/firmware/config.txt
fi
'';
};
# Turny service
systemd.services.turny = {
description = "Turny Spotify RFID Controller";
documentation = [ "https://github.com/repomaa/turny" ];
after = [
"network.target"
"sound.target"
];
wants = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = lib.getExe inputs.turny.packages.${pkgs.stdenv.hostPlatform.system}.default;
User = "turny";
Group = "turny";
WorkingDirectory = "/var/lib/turny";
Restart = "always";
RestartSec = 10;
RestartPreventExitStatus = 23;
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [ "/var/lib/turny" ];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
LimitNOFILE = 1024;
MemoryAccounting = true;
MemoryMax = "100M";
StandardOutput = "journal";
StandardError = "journal";
SyslogIdentifier = "turny";
};
environment = {
RUST_LOG = "info";
RUST_BACKTRACE = "1";
};
};
users.users.turny = {
isSystemUser = true;
group = "turny";
extraGroups = [
"gpio"
"spi"
"audio"
];
home = "/var/lib/turny";
createHome = true;
};
users.groups.turny = { };
users.groups.gpio = { };
users.groups.spi = { };
# Udev rules for GPIO and SPI access
services.udev.extraRules = ''
SUBSYSTEM=="gpio", GROUP="gpio", MODE="0660"
SUBSYSTEM=="gpiomem", GROUP="gpio", MODE="0660"
SUBSYSTEM=="spidev", GROUP="spi", MODE="0660"
'';
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# settings for stateful data, like user locations and database versions
# on the system were taken. It's perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "25.05"; # Did you read the comment?
sdImage.compressImage = false;
}