mirror of
https://github.com/nix-community/raspberry-pi-nix.git
synced 2025-11-08 19:46:03 +01:00
init
This commit is contained in:
commit
3d7a565149
17 changed files with 831 additions and 0 deletions
102
README.md
Normal file
102
README.md
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
# raspberry-pi-nix
|
||||||
|
|
||||||
|
NixOS modules that make building images for raspberry-pi products
|
||||||
|
easier. Most of the work in this repository is based on work in
|
||||||
|
[nixos-hardware](https://github.com/NixOS/nixos-hardware) and
|
||||||
|
[nixpkgs](https://github.com/NixOS/nixpkgs). Additionally, be aware
|
||||||
|
that I am no expert and this repo is the product of me fooling around
|
||||||
|
with some pis.
|
||||||
|
|
||||||
|
This flake provides nixos modules that correspond to different
|
||||||
|
raspberry-pi products. These modules can be included in nixos
|
||||||
|
configurations and aim to deliver the following benefits:
|
||||||
|
|
||||||
|
1. Configure the kernel, device tree, and u-boot in a way that is
|
||||||
|
compatible with the hardware.
|
||||||
|
2. Provide a nix interface to device tree configuration that will be
|
||||||
|
familiar to those who have used raspberry-pi's config.txt based
|
||||||
|
configuration.
|
||||||
|
3. Make it easy to build an image suitable for flashing to an sd-card,
|
||||||
|
without a need to first go through an installation media.
|
||||||
|
|
||||||
|
The important modules are `overlay/default.nix`, `rpi/default.nix`,
|
||||||
|
and `rpi/device-tree.nix`. The other modules for i2c, i2s, etc are
|
||||||
|
mostly wrappers that set common device tree settings for you.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
description = "raspberry-pi-nix example";
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11";
|
||||||
|
raspberry-pi-nix = {
|
||||||
|
url = "github:tstat/raspberry-pi-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, raspberry-pi-nix }:
|
||||||
|
let
|
||||||
|
inherit (nixpkgs.lib) nixosSystem;
|
||||||
|
basic-config = { pkgs, lib, ... }: {
|
||||||
|
time.timeZone = "America/New_York";
|
||||||
|
users.users.root.initialPassword = "root";
|
||||||
|
networking = {
|
||||||
|
hostName = "basic-example";
|
||||||
|
useDHCP = false;
|
||||||
|
interfaces = { wlan0.useDHCP = true; };
|
||||||
|
};
|
||||||
|
hardware.raspberry-pi = {
|
||||||
|
i2c.enable = true;
|
||||||
|
audio.enable = true;
|
||||||
|
fkms-3d.enable = true;
|
||||||
|
deviceTree = {
|
||||||
|
dt-overlays = [{
|
||||||
|
overlay = "imx477"; # add the overlay for the HQ camera
|
||||||
|
args = [ ];
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
nixosConfigurations = {
|
||||||
|
rpi-zero-2-w-example = nixosSystem {
|
||||||
|
system = "aarch64-linux";
|
||||||
|
modules = [ raspberry-pi-nix.rpi-zero-2-w basic-config ];
|
||||||
|
};
|
||||||
|
rpi-4b-example = nixosSystem {
|
||||||
|
system = "aarch64-linux";
|
||||||
|
modules = [ raspberry-pi-nix.rpi-4b basic-config ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building an sd-card image
|
||||||
|
|
||||||
|
An image suitable for flashing to an sd-card can be found at the
|
||||||
|
attribute `config.system.build.sdImage`. For example, if you wanted to
|
||||||
|
build an image for `rpi-zero-2-w-example` in the above configuration
|
||||||
|
example you could run:
|
||||||
|
|
||||||
|
```
|
||||||
|
nix build '.#nixosConfigurations.rpi-zero-2-w-example.config.system.build.sdImage'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other notes
|
||||||
|
|
||||||
|
The sd-image built is partitioned in the same way as the aarch64
|
||||||
|
installation media from nixpkgs: There is a firmware partition that
|
||||||
|
contains necessary firmware, u-boot, and config.txt. Then there is
|
||||||
|
another partition that contains everything else. After the sd-image is
|
||||||
|
built, nixos system updates will not change anything in the firmware
|
||||||
|
partition ever again. New kernels and device tree configurations will
|
||||||
|
remain on the nixos partition and be booted by u-boot in the firmware
|
||||||
|
partition.
|
||||||
|
|
||||||
|
So, while you can control device tree params and overlays through your
|
||||||
|
nixos system configuration, if you want to modify other config.txt
|
||||||
|
variables this must be done manually by mounting the partition and
|
||||||
|
modifying the config.txt file.
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1652182392,
|
||||||
|
"narHash": "sha256-H9Bmor+kfogrE0X7Fi5sh0gCUWDG4pnmYxedJyIT41A=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "aa2f845096f72dde4ad0c168eeec387cbd2eae04",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-21.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
16
flake.nix
Normal file
16
flake.nix
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
description = "raspberry-pi nixos configuration";
|
||||||
|
|
||||||
|
inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11"; };
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }: {
|
||||||
|
overlay = import ./overlay;
|
||||||
|
rpi = import ./rpi {
|
||||||
|
nixpkgs = nixpkgs;
|
||||||
|
overlay = self.overlay;
|
||||||
|
};
|
||||||
|
rpi-3b-plus = import ./rpi-3b-plus self.rpi;
|
||||||
|
rpi-4b = import ./rpi-4b self.rpi;
|
||||||
|
rpi-zero-2-w = import ./rpi-zero-2-w self.rpi;
|
||||||
|
};
|
||||||
|
}
|
||||||
51
overlay/default.nix
Normal file
51
overlay/default.nix
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
final: prev: {
|
||||||
|
# newer version of libcamera
|
||||||
|
libcamera = prev.libcamera.overrideAttrs (old: {
|
||||||
|
src = prev.fetchgit {
|
||||||
|
url = "https://git.libcamera.org/libcamera/libcamera.git";
|
||||||
|
rev = "44d59841e1ce59042b8069b8078bc9f7b1bfa73b";
|
||||||
|
sha256 = "1nzkvy2y772ak9gax456ws2fmjc9ncams0m1w27h1rzpxn5yphqr";
|
||||||
|
};
|
||||||
|
mesonFlags = [ "-Dv4l2=true" "-Dqcam=disabled" "-Dlc-compliance=disabled" ];
|
||||||
|
patches = (old.patches or [ ]) ++ [ ./libcamera.patch ];
|
||||||
|
});
|
||||||
|
|
||||||
|
libcamera-apps = final.callPackage ./libcamera-apps.nix { };
|
||||||
|
|
||||||
|
# newer version of rpi firmware
|
||||||
|
raspberrypifw = prev.raspberrypifw.overrideAttrs (old: {
|
||||||
|
src = prev.fetchFromGitHub {
|
||||||
|
owner = "raspberrypi";
|
||||||
|
repo = "firmware";
|
||||||
|
rev = "2cf8a179b3f2e6e5e5ceba4e8e544def10a49020";
|
||||||
|
sha256 = "YG1bryflbV3W62MhZ/XMSgUJXMhCl/fe86x+CT7XZ4U=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
# provide generic rpi arm64 u-boot
|
||||||
|
uboot_rpi_arm64 = prev.buildUBoot rec {
|
||||||
|
defconfig = "rpi_arm64_defconfig";
|
||||||
|
extraMeta.platforms = [ "aarch64-linux" ];
|
||||||
|
filesToInstall = [ "u-boot.bin" ];
|
||||||
|
version = "2022.04";
|
||||||
|
src = prev.fetchurl {
|
||||||
|
url = "ftp://ftp.denx.de/pub/u-boot/u-boot-${version}.tar.bz2";
|
||||||
|
sha256 = "1l5w13dznj0z1ibqv2d6ljx2ma1gnf5x5ay3dqkqwxr6750nbq38";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# use a newer version of the rpi linux kernel fork
|
||||||
|
linux_rpi = prev.linux_rpi4.override {
|
||||||
|
argsOverride = rec {
|
||||||
|
src = prev.fetchFromGitHub {
|
||||||
|
owner = "raspberrypi";
|
||||||
|
repo = "linux";
|
||||||
|
rev = "9af1cc301e4dffb830025207a54d0bc63bec16c7";
|
||||||
|
sha256 = "fsMTUdz1XZhPaSXpU1uBV4V4VxoZKi6cwP0QJcrCy1o=";
|
||||||
|
fetchSubmodules = true;
|
||||||
|
};
|
||||||
|
version = "5.15.36";
|
||||||
|
modDirVersion = "5.15.36";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
33
overlay/libcamera-apps.nix
Normal file
33
overlay/libcamera-apps.nix
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{ lib, stdenv, fetchFromGitHub, fetchpatch, cmake, pkg-config, libjpeg, libtiff
|
||||||
|
, libpng, libcamera, libepoxy, boost, libexif }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "libcamera-apps";
|
||||||
|
version = "unstable-2022-05-12";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "raspberrypi";
|
||||||
|
repo = "libcamera-apps";
|
||||||
|
rev = "f5a2f1d86b440ebc064d4369421348d858ef31f3";
|
||||||
|
sha256 = "Et8enICYct/AvWstY/id6BD/NB9+La9pNrtAsdwv+Tg=";
|
||||||
|
fetchSubmodules = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [ cmake pkg-config ];
|
||||||
|
buildInputs = [ libjpeg libtiff libcamera libepoxy boost libexif libpng ];
|
||||||
|
cmakeFlags = [
|
||||||
|
"-DENABLE_QT=0"
|
||||||
|
"-DENABLE_OPENCV=0"
|
||||||
|
"-DENABLE_TFLITE=0"
|
||||||
|
"-DENABLE_X11=1"
|
||||||
|
"-DENABLE_DRM=1"
|
||||||
|
(if (stdenv.hostPlatform.isAarch64) then "-DARM64=ON" else "-DARM64=OFF")
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Userland tools interfacing with Raspberry Pi cameras";
|
||||||
|
homepage = "https://github.com/raspberrypi/libcamera-apps";
|
||||||
|
license = licenses.bsd2;
|
||||||
|
platforms = [ "aarch64-linux" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
19
overlay/libcamera.patch
Normal file
19
overlay/libcamera.patch
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
diff --git a/src/libcamera/source_paths.cpp b/src/libcamera/source_paths.cpp
|
||||||
|
index 19689585..1380dfae 100644
|
||||||
|
--- a/src/libcamera/source_paths.cpp
|
||||||
|
+++ b/src/libcamera/source_paths.cpp
|
||||||
|
@@ -39,14 +39,6 @@ namespace {
|
||||||
|
*/
|
||||||
|
bool isLibcameraInstalled()
|
||||||
|
{
|
||||||
|
- /*
|
||||||
|
- * DT_RUNPATH (DT_RPATH when the linker uses old dtags) is removed on
|
||||||
|
- * install.
|
||||||
|
- */
|
||||||
|
- for (const ElfW(Dyn) *dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn) {
|
||||||
|
- if (dyn->d_tag == DT_RUNPATH || dyn->d_tag == DT_RPATH)
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
15
rpi-3b-plus/default.nix
Normal file
15
rpi-3b-plus/default.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
rpi:
|
||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ rpi ];
|
||||||
|
hardware.raspberry-pi.deviceTree = {
|
||||||
|
base-dtb = "bcm2710-rpi-3-b-plus.dtb";
|
||||||
|
# u-boot expects bcm2837-rpi-3-b-plus.dtb for the 3b+ (as of
|
||||||
|
# 2020.04), although the kernel has 2710. We rename it to satisfy
|
||||||
|
# u-boot for now.
|
||||||
|
postInstall = ''
|
||||||
|
mv $out/broadcom/bcm2710-rpi-3-b-plus.dtb $out/broadcom/bcm2837-rpi-3-b-plus.dtb
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
8
rpi-4b/default.nix
Normal file
8
rpi-4b/default.nix
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
rpi:
|
||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ rpi ];
|
||||||
|
hardware.raspberry-pi.deviceTree.base-dtb = "bcm2711-rpi-4-b.dtb";
|
||||||
|
}
|
||||||
|
|
||||||
13
rpi-zero-2-w/default.nix
Normal file
13
rpi-zero-2-w/default.nix
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
rpi:
|
||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ rpi ];
|
||||||
|
hardware.raspberry-pi.deviceTree.base-dtb = "bcm2710-rpi-zero-2.dtb";
|
||||||
|
# u-boot expects bcm2837-rpi-zero-2.dtb for the zero 2 w (as of
|
||||||
|
# 2020.04), although the kernel has 2710. We rename it to satisfy
|
||||||
|
# u-boot for now.
|
||||||
|
hardware.raspberry-pi.deviceTree.postInstall = ''
|
||||||
|
mv $out/broadcom/bcm2710-rpi-zero-2.dtb $out/broadcom/bcm2837-rpi-zero-2.dtb
|
||||||
|
'';
|
||||||
|
}
|
||||||
17
rpi/audio.nix
Normal file
17
rpi/audio.nix
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.hardware.raspberry-pi.audio;
|
||||||
|
in {
|
||||||
|
options.hardware.raspberry-pi.audio = {
|
||||||
|
enable = lib.mkEnableOption "configuration for audio";
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
hardware = {
|
||||||
|
raspberry-pi.deviceTree.base-dtb-params = [ "audio=on" ];
|
||||||
|
pulseaudio.configFile = lib.mkOverride 990
|
||||||
|
(pkgs.runCommand "default.pa" { } ''
|
||||||
|
sed 's/module-udev-detect$/module-udev-detect tsched=0/' ${config.hardware.pulseaudio.package}/etc/pulse/default.pa > $out
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
26
rpi/default.nix
Normal file
26
rpi/default.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{ overlay, nixpkgs }:
|
||||||
|
{ lib, pkgs, config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(import ../sd-image nixpkgs)
|
||||||
|
./device-tree.nix
|
||||||
|
./audio.nix
|
||||||
|
./i2c.nix
|
||||||
|
./i2s.nix
|
||||||
|
./modesetting.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
nixpkgs = { overlays = [ overlay ]; };
|
||||||
|
boot = {
|
||||||
|
kernelPackages = pkgs.linuxPackagesFor (pkgs.linux_rpi);
|
||||||
|
initrd.availableKernelModules = [ "usbhid" "usb_storage" "vc4" ];
|
||||||
|
|
||||||
|
loader = {
|
||||||
|
grub.enable = lib.mkDefault false;
|
||||||
|
generic-extlinux-compatible.enable = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
hardware.enableRedistributableFirmware = true;
|
||||||
|
|
||||||
|
}
|
||||||
97
rpi/device-tree.nix
Normal file
97
rpi/device-tree.nix
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.hardware.raspberry-pi.deviceTree;
|
||||||
|
in {
|
||||||
|
options.hardware.raspberry-pi.deviceTree = {
|
||||||
|
base-dtb = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
example = "bcm2711-rpi-4-b.dtb";
|
||||||
|
description = "base dtb to apply";
|
||||||
|
};
|
||||||
|
base-dtb-params = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.string;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "i2c1=on" "audio=on" ];
|
||||||
|
description = "parameters to pass to the base dtb";
|
||||||
|
};
|
||||||
|
dt-overlays = lib.mkOption {
|
||||||
|
type = with lib.types;
|
||||||
|
listOf (submodule {
|
||||||
|
options = {
|
||||||
|
overlay = lib.mkOption { type = str; };
|
||||||
|
args = lib.mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [ ];
|
||||||
|
example = [{
|
||||||
|
overlay = "vc4-fkms-v3d";
|
||||||
|
args = [ "cma-512" ];
|
||||||
|
}];
|
||||||
|
description = "dtb overlays to apply";
|
||||||
|
};
|
||||||
|
postInstall = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
description = "bash command to run after building dtb";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
hardware = {
|
||||||
|
deviceTree = {
|
||||||
|
enable = true;
|
||||||
|
filter = cfg.base-dtb;
|
||||||
|
package = let
|
||||||
|
dtbsWithSymbols = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "dtbs-with-symbols";
|
||||||
|
inherit (config.boot.kernelPackages.kernel)
|
||||||
|
src nativeBuildInputs depsBuildBuild;
|
||||||
|
patches = map (patch: patch.patch)
|
||||||
|
config.boot.kernelPackages.kernel.kernelPatches;
|
||||||
|
buildPhase = ''
|
||||||
|
patchShebangs scripts/*
|
||||||
|
substituteInPlace scripts/Makefile.lib \
|
||||||
|
--replace 'DTC_FLAGS += $(DTC_FLAGS_$(basetarget))' 'DTC_FLAGS += $(DTC_FLAGS_$(basetarget)) -@'
|
||||||
|
make ${pkgs.stdenv.hostPlatform.linux-kernel.baseConfig} ARCH="${pkgs.stdenv.hostPlatform.linuxArch}"
|
||||||
|
make dtbs ARCH="${pkgs.stdenv.hostPlatform.linuxArch}"
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
make dtbs_install INSTALL_DTBS_PATH=$out/dtbs ARCH="${pkgs.stdenv.hostPlatform.linuxArch}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in lib.mkForce (pkgs.runCommand "device-tree-overlays" {
|
||||||
|
buildInputs = with pkgs; [ findutils libraspberrypi ];
|
||||||
|
} ''
|
||||||
|
cd ${dtbsWithSymbols}/dtbs
|
||||||
|
for dtb in $(find . -type f -name "${config.hardware.deviceTree.filter}")
|
||||||
|
do
|
||||||
|
install -D $dtb $out/$dtb
|
||||||
|
|
||||||
|
${
|
||||||
|
lib.concatMapStrings (param: ''
|
||||||
|
dtmerge -d $out/$dtb{,-merged} - ${param}
|
||||||
|
mv $out/$dtb{-merged,}
|
||||||
|
'') cfg.base-dtb-params
|
||||||
|
}
|
||||||
|
|
||||||
|
${
|
||||||
|
lib.concatMapStrings (x: ''
|
||||||
|
dtmerge -d $out/$dtb{,-merged} ${x.overlay} ${
|
||||||
|
builtins.concatStringsSep " " x.args
|
||||||
|
}
|
||||||
|
mv $out/$dtb{-merged,}
|
||||||
|
'') (map (x:
|
||||||
|
x // {
|
||||||
|
overlay =
|
||||||
|
"${config.boot.kernelPackages.kernel}/dtbs/overlays/${x.overlay}.dtbo";
|
||||||
|
}) cfg.dt-overlays)
|
||||||
|
}
|
||||||
|
done
|
||||||
|
${cfg.postInstall}
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
14
rpi/i2c.nix
Normal file
14
rpi/i2c.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.hardware.raspberry-pi.i2c;
|
||||||
|
in {
|
||||||
|
options.hardware.raspberry-pi.i2c = {
|
||||||
|
enable = lib.mkEnableOption "configuration for i2c";
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
hardware = {
|
||||||
|
raspberry-pi.deviceTree.base-dtb-params = [ "i2c1=on" ];
|
||||||
|
i2c.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
13
rpi/i2s.nix
Normal file
13
rpi/i2s.nix
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.hardware.raspberry-pi.i2s;
|
||||||
|
in {
|
||||||
|
options.hardware.raspberry-pi.i2s = {
|
||||||
|
enable = lib.mkEnableOption "configuration for i2s";
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
hardware = {
|
||||||
|
raspberry-pi.deviceTree.base-dtb-params = [ "i2s=on" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
23
rpi/modesetting.nix
Normal file
23
rpi/modesetting.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let cfg = config.hardware.raspberry-pi.fkms-3d;
|
||||||
|
in {
|
||||||
|
options.hardware.raspberry-pi.fkms-3d = {
|
||||||
|
enable = lib.mkEnableOption "Enable modesetting through fkms-3d";
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
hardware = {
|
||||||
|
raspberry-pi.deviceTree.dt-overlays = [
|
||||||
|
{
|
||||||
|
overlay = "cma";
|
||||||
|
args = [ ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
overlay = "vc4-fkms-v3d";
|
||||||
|
args = [ ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
services.xserver.videoDrivers = lib.mkBefore [ "modesetting" "fbdev" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
76
sd-image/default.nix
Normal file
76
sd-image/default.nix
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
stable:
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ (import ./sd-image.nix stable) ];
|
||||||
|
|
||||||
|
boot.loader.grub.enable = false;
|
||||||
|
boot.loader.generic-extlinux-compatible.enable = true;
|
||||||
|
|
||||||
|
boot.consoleLogLevel = lib.mkDefault 7;
|
||||||
|
|
||||||
|
# The serial ports listed here are:
|
||||||
|
# - ttyS0: for Tegra (Jetson TX1)
|
||||||
|
# - ttyAMA0: for QEMU's -machine virt
|
||||||
|
boot.kernelParams =
|
||||||
|
[ "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0" ];
|
||||||
|
|
||||||
|
sdImage = {
|
||||||
|
populateFirmwareCommands = let
|
||||||
|
configTxt = pkgs.writeText "config.txt" ''
|
||||||
|
[pi02]
|
||||||
|
kernel=u-boot-rpi_arm64.bin
|
||||||
|
|
||||||
|
[pi3+]
|
||||||
|
kernel=u-boot-rpi_arm64.bin
|
||||||
|
|
||||||
|
[pi4]
|
||||||
|
kernel=u-boot-rpi4.bin
|
||||||
|
enable_gic=1
|
||||||
|
armstub=armstub8-gic.bin
|
||||||
|
arm_boost=1
|
||||||
|
|
||||||
|
# Otherwise the resolution will be weird in most cases, compared to
|
||||||
|
# what the pi3 firmware does by default.
|
||||||
|
disable_overscan=1
|
||||||
|
|
||||||
|
[all]
|
||||||
|
# Boot in 64-bit mode.
|
||||||
|
arm_64bit=1
|
||||||
|
|
||||||
|
# U-Boot needs this to work, regardless of whether UART is actually used or not.
|
||||||
|
# Look in arch/arm/mach-bcm283x/Kconfig in the U-Boot tree to see if this is still
|
||||||
|
# a requirement in the future.
|
||||||
|
enable_uart=1
|
||||||
|
|
||||||
|
# Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
|
||||||
|
# when attempting to show low-voltage or overtemperature warnings.
|
||||||
|
avoid_warnings=1
|
||||||
|
'';
|
||||||
|
in ''
|
||||||
|
(cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/)
|
||||||
|
|
||||||
|
# Add the config
|
||||||
|
cp ${configTxt} firmware/config.txt
|
||||||
|
|
||||||
|
# Add rpi generic u-boot
|
||||||
|
cp ${pkgs.uboot_rpi_arm64}/u-boot.bin firmware/u-boot-rpi_arm64.bin
|
||||||
|
|
||||||
|
# Add pi3 specific files
|
||||||
|
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-3-b-plus.dtb firmware/
|
||||||
|
|
||||||
|
# Add pi4 specific files
|
||||||
|
cp ${pkgs.ubootRaspberryPi4_64bit}/u-boot.bin firmware/u-boot-rpi4.bin
|
||||||
|
cp ${pkgs.raspberrypi-armstubs}/armstub8-gic.bin firmware/armstub8-gic.bin
|
||||||
|
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2711-rpi-4-b.dtb firmware/
|
||||||
|
|
||||||
|
# Add pi-zero-2 specific files
|
||||||
|
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-zero-2.dtb firmware/
|
||||||
|
cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/bcm2710-rpi-zero-2-w.dtb firmware/
|
||||||
|
'';
|
||||||
|
populateRootCommands = ''
|
||||||
|
mkdir -p ./files/boot
|
||||||
|
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
281
sd-image/sd-image.nix
Normal file
281
sd-image/sd-image.nix
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
nixpkgs:
|
||||||
|
# This module was lifted from nixpkgs installer code. It is modified
|
||||||
|
# so as to not import all-hardware. The goal here is to write the
|
||||||
|
# nixos image for a raspberry pi to an sd-card in a way so that we can
|
||||||
|
# pop it in and go. We don't need to support many possible hardware
|
||||||
|
# targets since we know we are targeting raspberry pi products.
|
||||||
|
|
||||||
|
# This module creates a bootable SD card image containing the given NixOS
|
||||||
|
# configuration. The generated image is MBR partitioned, with a FAT
|
||||||
|
# /boot/firmware partition, and ext4 root partition. The generated image
|
||||||
|
# is sized to fit its contents, and a boot script automatically resizes
|
||||||
|
# the root partition to fit the device on the first boot.
|
||||||
|
#
|
||||||
|
# The firmware partition is built with expectation to hold the Raspberry
|
||||||
|
# Pi firmware and bootloader, and be removed and replaced with a firmware
|
||||||
|
# build for the target SoC for other board families.
|
||||||
|
#
|
||||||
|
# The derivation for the SD image will be placed in
|
||||||
|
# config.system.build.sdImage
|
||||||
|
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
rootfsImage = pkgs.callPackage "${nixpkgs}/nixos/lib/make-ext4-fs.nix" ({
|
||||||
|
inherit (config.sdImage) storePaths;
|
||||||
|
compressImage = true;
|
||||||
|
populateImageCommands = config.sdImage.populateRootCommands;
|
||||||
|
volumeLabel = "NIXOS_SD";
|
||||||
|
} // optionalAttrs (config.sdImage.rootPartitionUUID != null) {
|
||||||
|
uuid = config.sdImage.rootPartitionUUID;
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
imports = [ ];
|
||||||
|
|
||||||
|
options.sdImage = {
|
||||||
|
imageName = mkOption {
|
||||||
|
default =
|
||||||
|
"${config.sdImage.imageBaseName}-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}.img";
|
||||||
|
description = ''
|
||||||
|
Name of the generated image file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
imageBaseName = mkOption {
|
||||||
|
default = "nixos-sd-image";
|
||||||
|
description = ''
|
||||||
|
Prefix of the name of the generated image file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
storePaths = mkOption {
|
||||||
|
type = with types; listOf package;
|
||||||
|
example = literalExpression "[ pkgs.stdenv ]";
|
||||||
|
description = ''
|
||||||
|
Derivations to be included in the Nix store in the generated SD image.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firmwarePartitionOffset = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 8;
|
||||||
|
description = ''
|
||||||
|
Gap in front of the /boot/firmware partition, in mebibytes (1024×1024
|
||||||
|
bytes).
|
||||||
|
Can be increased to make more space for boards requiring to dd u-boot
|
||||||
|
SPL before actual partitions.
|
||||||
|
|
||||||
|
Unless you are building your own images pre-configured with an
|
||||||
|
installed U-Boot, you can instead opt to delete the existing `FIRMWARE`
|
||||||
|
partition, which is used **only** for the Raspberry Pi family of
|
||||||
|
hardware.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firmwarePartitionID = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "0x2178694e";
|
||||||
|
description = ''
|
||||||
|
Volume ID for the /boot/firmware partition on the SD card. This value
|
||||||
|
must be a 32-bit hexadecimal number.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firmwarePartitionName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "FIRMWARE";
|
||||||
|
description = ''
|
||||||
|
Name of the filesystem which holds the boot firmware.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
rootPartitionUUID = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = "14e19a7b-0ae0-484d-9d54-43bd6fdc20c7";
|
||||||
|
description = ''
|
||||||
|
UUID for the filesystem on the main NixOS partition on the SD card.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firmwareSize = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
# As of 2019-08-18 the Raspberry pi firmware + u-boot takes ~18MiB
|
||||||
|
default = 30;
|
||||||
|
description = ''
|
||||||
|
Size of the /boot/firmware partition, in megabytes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
populateFirmwareCommands = mkOption {
|
||||||
|
example =
|
||||||
|
literalExpression "'' cp \${pkgs.myBootLoader}/u-boot.bin firmware/ ''";
|
||||||
|
description = ''
|
||||||
|
Shell commands to populate the ./firmware directory.
|
||||||
|
All files in that directory are copied to the
|
||||||
|
/boot/firmware partition on the SD image.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
populateRootCommands = mkOption {
|
||||||
|
example = literalExpression
|
||||||
|
"''\${config.boot.loader.generic-extlinux-compatible.populateCmd} -c \${config.system.build.toplevel} -d ./files/boot''";
|
||||||
|
description = ''
|
||||||
|
Shell commands to populate the ./files directory.
|
||||||
|
All files in that directory are copied to the
|
||||||
|
root (/) partition on the SD image. Use this to
|
||||||
|
populate the ./files/boot (/boot) directory.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
postBuildCommands = mkOption {
|
||||||
|
example = literalExpression
|
||||||
|
"'' dd if=\${pkgs.myBootLoader}/SPL of=$img bs=1024 seek=1 conv=notrunc ''";
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Shell commands to run after the image is built.
|
||||||
|
Can be used for boards requiring to dd u-boot SPL before actual partitions.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
compressImage = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether the SD image should be compressed using
|
||||||
|
<command>zstd</command>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
expandOnBoot = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to configure the sd image to expand it's partition on boot.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
fileSystems = {
|
||||||
|
"/boot/firmware" = {
|
||||||
|
device = "/dev/disk/by-label/${config.sdImage.firmwarePartitionName}";
|
||||||
|
fsType = "vfat";
|
||||||
|
# Alternatively, this could be removed from the configuration.
|
||||||
|
# The filesystem is not needed at runtime, it could be treated
|
||||||
|
# as an opaque blob instead of a discrete FAT32 filesystem.
|
||||||
|
options = [ "nofail" "noauto" ];
|
||||||
|
};
|
||||||
|
"/" = {
|
||||||
|
device = "/dev/disk/by-label/NIXOS_SD";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sdImage.storePaths = [ config.system.build.toplevel ];
|
||||||
|
|
||||||
|
system.build.sdImage = pkgs.callPackage
|
||||||
|
({ stdenv, dosfstools, e2fsprogs, mtools, libfaketime, util-linux, zstd }:
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = config.sdImage.imageName;
|
||||||
|
|
||||||
|
nativeBuildInputs =
|
||||||
|
[ dosfstools e2fsprogs mtools libfaketime util-linux zstd ];
|
||||||
|
|
||||||
|
inherit (config.sdImage) compressImage;
|
||||||
|
|
||||||
|
buildCommand = ''
|
||||||
|
mkdir -p $out/nix-support $out/sd-image
|
||||||
|
export img=$out/sd-image/${config.sdImage.imageName}
|
||||||
|
|
||||||
|
echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system
|
||||||
|
if test -n "$compressImage"; then
|
||||||
|
echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products
|
||||||
|
else
|
||||||
|
echo "file sd-image $img" >> $out/nix-support/hydra-build-products
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Decompressing rootfs image"
|
||||||
|
zstd -d --no-progress "${rootfsImage}" -o ./root-fs.img
|
||||||
|
|
||||||
|
# Gap in front of the first partition, in MiB
|
||||||
|
gap=${toString config.sdImage.firmwarePartitionOffset}
|
||||||
|
|
||||||
|
# Create the image file sized to fit /boot/firmware and /, plus slack for the gap.
|
||||||
|
rootSizeBlocks=$(du -B 512 --apparent-size ./root-fs.img | awk '{ print $1 }')
|
||||||
|
firmwareSizeBlocks=$((${
|
||||||
|
toString config.sdImage.firmwareSize
|
||||||
|
} * 1024 * 1024 / 512))
|
||||||
|
imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024))
|
||||||
|
truncate -s $imageSize $img
|
||||||
|
|
||||||
|
# type=b is 'W95 FAT32', type=83 is 'Linux'.
|
||||||
|
# The "bootable" partition is where u-boot will look file for the bootloader
|
||||||
|
# information (dtbs, extlinux.conf file).
|
||||||
|
sfdisk $img <<EOF
|
||||||
|
label: dos
|
||||||
|
label-id: ${config.sdImage.firmwarePartitionID}
|
||||||
|
|
||||||
|
start=''${gap}M, size=$firmwareSizeBlocks, type=b
|
||||||
|
start=$((gap + ${
|
||||||
|
toString config.sdImage.firmwareSize
|
||||||
|
}))M, type=83, bootable
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Copy the rootfs into the SD image
|
||||||
|
eval $(partx $img -o START,SECTORS --nr 2 --pairs)
|
||||||
|
dd conv=notrunc if=./root-fs.img of=$img seek=$START count=$SECTORS
|
||||||
|
|
||||||
|
# Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img
|
||||||
|
eval $(partx $img -o START,SECTORS --nr 1 --pairs)
|
||||||
|
truncate -s $((SECTORS * 512)) firmware_part.img
|
||||||
|
faketime "1970-01-01 00:00:00" mkfs.vfat -i ${config.sdImage.firmwarePartitionID} -n ${config.sdImage.firmwarePartitionName} firmware_part.img
|
||||||
|
|
||||||
|
# Populate the files intended for /boot/firmware
|
||||||
|
mkdir firmware
|
||||||
|
${config.sdImage.populateFirmwareCommands}
|
||||||
|
|
||||||
|
# Copy the populated /boot/firmware into the SD image
|
||||||
|
(cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::)
|
||||||
|
# Verify the FAT partition before copying it.
|
||||||
|
fsck.vfat -vn firmware_part.img
|
||||||
|
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
|
||||||
|
|
||||||
|
${config.sdImage.postBuildCommands}
|
||||||
|
|
||||||
|
if test -n "$compressImage"; then
|
||||||
|
zstd -T$NIX_BUILD_CORES --rm $img
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}) { };
|
||||||
|
|
||||||
|
boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot ''
|
||||||
|
# On the first boot do some maintenance tasks
|
||||||
|
if [ -f /nix-path-registration ]; then
|
||||||
|
set -euo pipefail
|
||||||
|
set -x
|
||||||
|
# Figure out device names for the boot device and root filesystem.
|
||||||
|
rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /)
|
||||||
|
bootDevice=$(lsblk -npo PKNAME $rootPart)
|
||||||
|
partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
|
||||||
|
|
||||||
|
# Resize the root partition and the filesystem to fit the disk
|
||||||
|
echo ",+," | sfdisk -N$partNum --no-reread $bootDevice
|
||||||
|
${pkgs.parted}/bin/partprobe
|
||||||
|
${pkgs.e2fsprogs}/bin/resize2fs $rootPart
|
||||||
|
|
||||||
|
# Register the contents of the initial Nix store
|
||||||
|
${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration
|
||||||
|
|
||||||
|
# nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag.
|
||||||
|
touch /etc/NIXOS
|
||||||
|
${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||||
|
|
||||||
|
# Prevents this from running on later boots.
|
||||||
|
rm -f /nix-path-registration
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue