1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.boot.loader.raspberryPi;
7
8 builderGeneric = pkgs.substituteAll {
9 src = ./builder.sh;
10 isExecutable = true;
11 inherit (pkgs) bash;
12 path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep];
13 firmware = pkgs.raspberrypifw;
14 version = cfg.version;
15 inherit configTxt;
16 };
17
18 inherit (pkgs.stdenv.hostPlatform) platform;
19
20 builderUboot = import ./builder_uboot.nix { inherit config; inherit pkgs; inherit configTxt; };
21
22 builder =
23 if cfg.uboot.enable then
24 "${builderUboot} -g ${toString cfg.uboot.configurationLimit} -t ${timeoutStr} -c"
25 else
26 builderGeneric;
27
28 blCfg = config.boot.loader;
29 timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout;
30
31 isAarch64 = pkgs.stdenv.isAarch64;
32 optional = pkgs.stdenv.lib.optionalString;
33
34 configTxt =
35 pkgs.writeText "config.txt" (''
36 # U-Boot used to need this to work, regardless of whether UART is actually used or not.
37 # TODO: check when/if this can be removed.
38 enable_uart=1
39
40 # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
41 # when attempting to show low-voltage or overtemperature warnings.
42 avoid_warnings=1
43 '' + optional isAarch64 ''
44 # Boot in 64-bit mode.
45 arm_control=0x200
46 '' + optional cfg.uboot.enable ''
47 kernel=u-boot-rpi.bin
48 '' + optional (cfg.firmwareConfig != null) cfg.firmwareConfig);
49
50in
51
52{
53 options = {
54
55 boot.loader.raspberryPi = {
56 enable = mkOption {
57 default = false;
58 type = types.bool;
59 description = ''
60 Whether to create files with the system generations in
61 <literal>/boot</literal>.
62 <literal>/boot/old</literal> will hold files from old generations.
63 '';
64 };
65
66 version = mkOption {
67 default = 2;
68 type = types.enum [ 1 2 3 ];
69 description = ''
70 '';
71 };
72
73 uboot = {
74 enable = mkOption {
75 default = false;
76 type = types.bool;
77 description = ''
78 Enable using uboot as bootmanager for the raspberry pi.
79 '';
80 };
81
82 configurationLimit = mkOption {
83 default = 20;
84 example = 10;
85 type = types.int;
86 description = ''
87 Maximum number of configurations in the boot menu.
88 '';
89 };
90
91 };
92
93 firmwareConfig = mkOption {
94 default = null;
95 type = types.nullOr types.string;
96 description = ''
97 Extra options that will be appended to <literal>/boot/config.txt</literal> file.
98 For possible values, see: https://www.raspberrypi.org/documentation/configuration/config-txt/
99 '';
100 };
101 };
102 };
103
104 config = mkIf cfg.enable {
105 assertions = singleton {
106 assertion = !pkgs.stdenv.isAarch64 || cfg.version == 3;
107 message = "Only Raspberry Pi 3 supports aarch64.";
108 };
109
110 system.build.installBootLoader = builder;
111 system.boot.loader.id = "raspberrypi";
112 system.boot.loader.kernelFile = platform.kernelTarget;
113 };
114}