diff --git a/nixops/device-tree-module.nix b/nixops/device-tree-module.nix new file mode 100644 index 0000000..b3f1dda --- /dev/null +++ b/nixops/device-tree-module.nix @@ -0,0 +1,67 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.hardware.deviceTree; +in { + options = { + hardware.deviceTree = { + enable = mkOption { + default = pkgs.stdenv.hostPlatform.platform.kernelDTB or false; + type = types.bool; + description = '' + Build device tree files. These are used to describe the + non-discoverable hardware of a system. + ''; + }; + + base = mkOption { + default = "${config.boot.kernelPackages.kernel}/dtbs"; + defaultText = "\${config.boot.kernelPackages.kernel}/dtbs"; + example = literalExample "pkgs.device-tree_rpi"; + type = types.path; + description = '' + The path containing the base device-tree (.dtb) to boot. Contains + device trees bundled with the Linux kernel by default. + ''; + }; + + name = mkOption { + default = null; + example = "some-dtb.dtb"; + type = types.nullOr types.str; + description = '' + The name of an explicit dtb to be loaded, relative to the dtb base. + Useful in extlinux scenarios if the bootloader doesn't pick the + right .dtb file from FDTDIR. + ''; + }; + + overlays = mkOption { + default = []; + example = literalExample + "[\"\${pkgs.device-tree_rpi.overlays}/w1-gpio.dtbo\"]"; + type = types.listOf types.path; + description = '' + A path containing device tree overlays (.dtbo) to be applied to all + base device-trees. + ''; + }; + + package = mkOption { + default = null; + type = types.nullOr types.path; + internal = true; + description = '' + A path containing the result of applying `overlays` to `base`. + ''; + }; + }; + }; + + config = mkIf (cfg.enable) { + hardware.deviceTree.package = if (cfg.overlays != []) + then pkgs.deviceTree.applyOverlays cfg.base cfg.overlays else cfg.base; + }; +} diff --git a/nixops/device-tree-pkg.nix b/nixops/device-tree-pkg.nix new file mode 100644 index 0000000..13d819a --- /dev/null +++ b/nixops/device-tree-pkg.nix @@ -0,0 +1,17 @@ +{ stdenvNoCC, dtc, findutils }: + +with stdenvNoCC.lib; { + applyOverlays = (base: overlays: stdenvNoCC.mkDerivation { + name = "device-tree-overlays"; + nativeBuildInputs = [ dtc findutils ]; + buildCommand = let + quotedDtbos = concatMapStringsSep " " (o: "\"${toString o}\"") (toList overlays); + in '' + for dtb in $(find ${base} -name "*.dtb" ); do + outDtb=$out/$(realpath --relative-to "${base}" "$dtb") + mkdir -p "$(dirname "$outDtb")" + fdtoverlay -o "$outDtb" -i "$dtb" ${quotedDtbos}; + done + ''; + }); +} diff --git a/nixops/rpi-server.nix b/nixops/rpi-server.nix index 684b87b..8c2f53a 100644 --- a/nixops/rpi-server.nix +++ b/nixops/rpi-server.nix @@ -20,9 +20,17 @@ boot.kernelParams = ["cma=64M"]; # work around https://github.com/raspberrypi/linux/issues/3208 boot.kernelPackages = if rpi4 then pkgs.linuxPackages_rpi4 else pkgs.linuxPackages_rpi3; boot.initrd.includeDefaultModules = false; + + # work around https://github.com/NixOS/nixpkgs/issues/125354 + disabledModules = [ "hardware/device-tree.nix" ]; + imports = [ ./device-tree-module.nix ]; + nixpkgs.config.packageOverrides = super: let self = super.pkgs; in { + deviceTree = super.callPackage ./device-tree-pkg.nix {}; + }; hardware.deviceTree.enable = true; - hardware.deviceTree.filter = "*rpi*.dtb"; - hardware.deviceTree.overlays = [ { name = "poe"; dtboFile = "${pkgs.device-tree_rpi.overlays}/rpi-poe.dtbo"; } ]; + hardware.deviceTree.base = pkgs.device-tree_rpi; + hardware.deviceTree.overlays = [ "${pkgs.device-tree_rpi.overlays}/rpi-poe.dtbo" ]; + fileSystems = { "/" = { diff --git a/nixops/rpi.nix b/nixops/rpi.nix index 16e92d3..3e006c9 100644 --- a/nixops/rpi.nix +++ b/nixops/rpi.nix @@ -16,9 +16,17 @@ in boot.kernelParams = if rpi4 then ["cma=64M"] else []; # work around https://github.com/raspberrypi/linux/issues/3208 boot.kernelPackages = if rpi4 then pkgs.linuxPackages_rpi4 else pkgs.linuxPackages_rpi3; boot.initrd.includeDefaultModules = false; + + # work around https://github.com/NixOS/nixpkgs/issues/125354 + disabledModules = [ "hardware/device-tree.nix" ]; + imports = [ ./device-tree-module.nix ]; + nixpkgs.config.packageOverrides = super: let self = super.pkgs; in { + deviceTree = super.callPackage ./device-tree-pkg.nix {}; + }; hardware.deviceTree.enable = true; - hardware.deviceTree.filter = "*rpi*.dtb"; - hardware.deviceTree.overlays = [ { name = "poe"; dtboFile = "${pkgs.device-tree_rpi.overlays}/rpi-poe.dtbo"; } ]; + hardware.deviceTree.base = pkgs.device-tree_rpi; + hardware.deviceTree.overlays = [ "${pkgs.device-tree_rpi.overlays}/rpi-poe.dtbo" ]; + fileSystems = { "/" = {