1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.boot.loader.raspberryPi;
7
8 builderUboot = import ./uboot-builder.nix { inherit pkgs configTxt; inherit (cfg) version; };
9 builderGeneric = import ./raspberrypi-builder.nix { inherit pkgs configTxt; };
10
11 builder =
12 if cfg.uboot.enable then
13 "${builderUboot} -g ${toString cfg.uboot.configurationLimit} -t ${timeoutStr} -c"
14 else
15 "${builderGeneric} -c";
16
17 blCfg = config.boot.loader;
18 timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout;
19
20 isAarch64 = pkgs.stdenv.hostPlatform.isAarch64;
21 optional = pkgs.lib.optionalString;
22
23 configTxt =
24 pkgs.writeText "config.txt" (''
25 # U-Boot used to need this to work, regardless of whether UART is actually used or not.
26 # TODO: check when/if this can be removed.
27 enable_uart=1
28
29 # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
30 # when attempting to show low-voltage or overtemperature warnings.
31 avoid_warnings=1
32 '' + optional isAarch64 ''
33 # Boot in 64-bit mode.
34 arm_64bit=1
35 '' + (if cfg.uboot.enable then ''
36 kernel=u-boot-rpi.bin
37 '' else ''
38 kernel=kernel.img
39 initramfs initrd followkernel
40 '') + optional (cfg.firmwareConfig != null) cfg.firmwareConfig);
41
42in
43
44{
45 options = {
46
47 boot.loader.raspberryPi = {
48 enable = mkOption {
49 default = false;
50 type = types.bool;
51 description = ''
52 Whether to create files with the system generations in
53 `/boot`.
54 `/boot/old` will hold files from old generations.
55
56 ::: {.note}
57 These options are deprecated, unsupported, and may not work like expected.
58 :::
59 '';
60 };
61
62 version = mkOption {
63 default = 2;
64 type = types.enum [ 0 1 2 3 4 ];
65 description = "";
66 };
67
68 uboot = {
69 enable = mkOption {
70 default = false;
71 type = types.bool;
72 description = ''
73 Enable using uboot as bootmanager for the raspberry pi.
74
75 ::: {.note}
76 These options are deprecated, unsupported, and may not work like expected.
77 :::
78 '';
79 };
80
81 configurationLimit = mkOption {
82 default = 20;
83 example = 10;
84 type = types.int;
85 description = ''
86 Maximum number of configurations in the boot menu.
87
88 ::: {.note}
89 These options are deprecated, unsupported, and may not work like expected.
90 :::
91 '';
92 };
93
94 };
95
96 firmwareConfig = mkOption {
97 default = null;
98 type = types.nullOr types.lines;
99 description = ''
100 Extra options that will be appended to `/boot/config.txt` file.
101 For possible values, see: https://www.raspberrypi.com/documentation/computers/config_txt.html
102
103 ::: {.note}
104 These options are deprecated, unsupported, and may not work like expected.
105 :::
106 '';
107 };
108 };
109 };
110
111 config = mkMerge[
112 (mkIf cfg.uboot.enable {
113 warnings = [
114 ''
115 The option set for `boot.loader.raspberrypi.uboot` has been recommended against
116 for years, and is now formally deprecated.
117
118 It is possible it already did not work like you expected.
119
120 It never worked on the Raspberry Pi 4 family.
121
122 These options will be removed by NixOS 24.11.
123 ''
124 ];
125 })
126 (mkIf cfg.enable {
127 warnings = [
128 ''
129 The option set for `boot.loader.raspberrypi` has been recommended against
130 for years, and is now formally deprecated.
131
132 It is possible it already did not work like you expected.
133
134 It never worked on the Raspberry Pi 4 family.
135
136 These options will be removed by NixOS 24.11.
137 ''
138 ];
139 })
140 (mkIf cfg.enable {
141 assertions = singleton {
142 assertion = !pkgs.stdenv.hostPlatform.isAarch64 || cfg.version >= 3;
143 message = "Only Raspberry Pi >= 3 supports aarch64.";
144 };
145
146 system.build.installBootLoader = builder;
147 system.boot.loader.id = "raspberrypi";
148 system.boot.loader.kernelFile = pkgs.stdenv.hostPlatform.linux-kernel.target;
149 })
150 ];
151}