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 = lib.mdDoc ''
52 Whether to create files with the system generations in
53 `/boot`.
54 `/boot/old` will hold files from old generations.
55 '';
56 };
57
58 version = mkOption {
59 default = 2;
60 type = types.enum [ 0 1 2 3 4 ];
61 description = lib.mdDoc "";
62 };
63
64 uboot = {
65 enable = mkOption {
66 default = false;
67 type = types.bool;
68 description = lib.mdDoc ''
69 Enable using uboot as bootmanager for the raspberry pi.
70 '';
71 };
72
73 configurationLimit = mkOption {
74 default = 20;
75 example = 10;
76 type = types.int;
77 description = lib.mdDoc ''
78 Maximum number of configurations in the boot menu.
79 '';
80 };
81
82 };
83
84 firmwareConfig = mkOption {
85 default = null;
86 type = types.nullOr types.lines;
87 description = lib.mdDoc ''
88 Extra options that will be appended to `/boot/config.txt` file.
89 For possible values, see: https://www.raspberrypi.com/documentation/computers/config_txt.html
90 '';
91 };
92 };
93 };
94
95 config = mkIf cfg.enable {
96 assertions = singleton {
97 assertion = !pkgs.stdenv.hostPlatform.isAarch64 || cfg.version >= 3;
98 message = "Only Raspberry Pi >= 3 supports aarch64.";
99 };
100
101 system.build.installBootLoader = builder;
102 system.boot.loader.id = "raspberrypi";
103 system.boot.loader.kernelFile = pkgs.stdenv.hostPlatform.linux-kernel.target;
104 };
105}