nixpkgs/nixos/modules/hardware/device-tree.nix
2024-08-30 00:30:34 +02:00

224 lines
6.9 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.hardware.deviceTree;
overlayType = lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
description = ''
Name of this overlay
'';
};
filter = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "*rpi*.dtb";
description = ''
Only apply to .dtb files matching glob expression.
'';
};
dtsFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
description = ''
Path to .dts overlay file, overlay is applied to
each .dtb file matching "compatible" of the overlay.
'';
default = null;
example = lib.literalExpression "./dts/overlays.dts";
};
dtsText = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Literal DTS contents, overlay is applied to
each .dtb file matching "compatible" of the overlay.
'';
example = ''
/dts-v1/;
/plugin/;
/ {
compatible = "raspberrypi";
};
&{/soc} {
pps {
compatible = "pps-gpio";
status = "okay";
};
};
'';
};
dtboFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to .dtbo compiled overlay file.
'';
};
};
};
filterDTBs = src: if cfg.filter == null
then src
else
pkgs.runCommand "dtbs-filtered" {} ''
mkdir -p $out
cd ${src}
find . -type f -name '${cfg.filter}' -print0 \
| xargs -0 cp -v --no-preserve=mode --target-directory $out --parents
'';
filteredDTBs = filterDTBs cfg.dtbSource;
# Fill in `dtboFile` for each overlay if not set already.
# Existence of one of these is guarded by assertion below
withDTBOs = xs: lib.flip map xs (o: o // { dtboFile =
let
includePaths = ["${lib.getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes"] ++ cfg.dtboBuildExtraIncludePaths;
extraPreprocessorFlags = cfg.dtboBuildExtraPreprocessorFlags;
in
if o.dtboFile == null then
let
dtsFile = if o.dtsFile == null then (pkgs.writeText "dts" o.dtsText) else o.dtsFile;
in
pkgs.deviceTree.compileDTS {
name = "${o.name}-dtbo";
inherit includePaths extraPreprocessorFlags dtsFile;
}
else o.dtboFile; } );
in
{
imports = [
(lib.mkRemovedOptionModule [ "hardware" "deviceTree" "base" ] "Use hardware.deviceTree.kernelPackage instead")
];
options = {
hardware.deviceTree = {
enable = lib.mkOption {
default = pkgs.stdenv.hostPlatform.linux-kernel.DTB or false;
type = lib.types.bool;
description = ''
Build device tree files. These are used to describe the
non-discoverable hardware of a system.
'';
};
kernelPackage = lib.mkOption {
default = config.boot.kernelPackages.kernel;
defaultText = lib.literalExpression "config.boot.kernelPackages.kernel";
example = lib.literalExpression "pkgs.linux_latest";
type = lib.types.path;
description = ''
Kernel package where device tree include directory is from. Also used as default source of dtb package to apply overlays to
'';
};
dtboBuildExtraPreprocessorFlags = lib.mkOption {
default = [];
example = lib.literalExpression "[ \"-DMY_DTB_DEFINE\" ]";
type = lib.types.listOf lib.types.str;
description = ''
Additional flags to pass to the preprocessor during dtbo compilations
'';
};
dtboBuildExtraIncludePaths = lib.mkOption {
default = [];
example = lib.literalExpression ''
[
./my_custom_include_dir_1
./custom_include_dir_2
]
'';
type = lib.types.listOf lib.types.path;
description = ''
Additional include paths that will be passed to the preprocessor when creating the final .dts to compile into .dtbo
'';
};
dtbSource = lib.mkOption {
default = "${cfg.kernelPackage}/dtbs";
defaultText = lib.literalExpression "\${cfg.kernelPackage}/dtbs";
type = lib.types.path;
description = ''
Path to dtb directory that overlays and other processing will be applied to. Uses
device trees bundled with the Linux kernel by default.
'';
};
name = lib.mkOption {
default = null;
example = "some-dtb.dtb";
type = lib.types.nullOr lib.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.
'';
};
filter = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "*rpi*.dtb";
description = ''
Only include .dtb files matching glob expression.
'';
};
overlays = lib.mkOption {
default = [];
example = lib.literalExpression ''
[
{ name = "pps"; dtsFile = ./dts/pps.dts; }
{ name = "spi";
dtsText = "...";
}
{ name = "precompiled"; dtboFile = ./dtbos/example.dtbo; }
]
'';
type = lib.types.listOf (lib.types.coercedTo lib.types.path (path: {
name = baseNameOf path;
filter = null;
dtboFile = path;
}) overlayType);
description = ''
List of overlays to apply to base device-tree (.dtb) files.
'';
};
package = lib.mkOption {
default = null;
type = lib.types.nullOr lib.types.path;
internal = true;
description = ''
A path containing the result of applying `overlays` to `kernelPackage`.
'';
};
};
};
config = lib.mkIf (cfg.enable) {
assertions = let
invalidOverlay = o: (o.dtsFile == null) && (o.dtsText == null) && (o.dtboFile == null);
in lib.singleton {
assertion = lib.all (o: !invalidOverlay o) cfg.overlays;
message = ''
deviceTree overlay needs one of dtsFile, dtsText or dtboFile set.
Offending overlay(s):
${toString (map (o: o.name) (builtins.filter invalidOverlay cfg.overlays))}
'';
};
hardware.deviceTree.package = if (cfg.overlays != [])
then pkgs.deviceTree.applyOverlays filteredDTBs (withDTBOs cfg.overlays)
else filteredDTBs;
};
}