- 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
246 lines
7.1 KiB
Nix
246 lines
7.1 KiB
Nix
# Edit this configuration file to define what should be installed on
|
|
# your system. Help is available in the configuration.nix(5) man page
|
|
# and in the NixOS manual (accessible by running `nixos-help`).
|
|
|
|
{
|
|
pkgs,
|
|
lib,
|
|
ssh,
|
|
config,
|
|
inputs,
|
|
...
|
|
}:
|
|
let
|
|
secrets = config.age.secrets;
|
|
in
|
|
{
|
|
nix = {
|
|
settings = {
|
|
experimental-features = [
|
|
"nix-command"
|
|
"flakes"
|
|
];
|
|
auto-optimise-store = true;
|
|
};
|
|
gc = {
|
|
automatic = true;
|
|
dates = "weekly";
|
|
options = "--delete-older-than 30d";
|
|
};
|
|
};
|
|
|
|
networking = {
|
|
hostName = "turny"; # Define your hostname.
|
|
useDHCP = true;
|
|
useNetworkd = true;
|
|
nftables.enable = true;
|
|
wireless = {
|
|
enable = true;
|
|
networks = {
|
|
KotiWLANi.pskRaw = "ext:psk_kotiwlani";
|
|
};
|
|
secretsFile = secrets.wpa_supplicant.path;
|
|
};
|
|
};
|
|
|
|
services.avahi = {
|
|
publish.enable = true;
|
|
};
|
|
|
|
services.tailscale = {
|
|
enable = true;
|
|
useRoutingFeatures = "client";
|
|
};
|
|
|
|
# Set your time zone.
|
|
time.timeZone = "Europe/Helsinki";
|
|
|
|
# Select internationalisation properties.
|
|
i18n.defaultLocale = "en_US.UTF-8";
|
|
|
|
# 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.
|
|
packages = [ pkgs.nh ];
|
|
openssh.authorizedKeys.keys = [ ssh.publicKeys.yubikey ];
|
|
initialPassword = "changeme";
|
|
};
|
|
users.users.root.openssh.authorizedKeys.keys = [ ssh.publicKeys.yubikey ];
|
|
|
|
nix.settings.trusted-users = [ "jokke" ];
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
vim
|
|
wget
|
|
htop
|
|
git
|
|
alsa-utils
|
|
];
|
|
|
|
# Enable the OpenSSH daemon.
|
|
services.openssh = {
|
|
enable = true;
|
|
settings.PasswordAuthentication = false;
|
|
};
|
|
|
|
modules.firewall = {
|
|
enable = true;
|
|
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 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;
|
|
}
|