├── .gitignore ├── overlays └── default.nix ├── platforms ├── rpi3 │ └── default.nix ├── rpizero │ └── default.nix ├── rpizero2 │ └── default.nix └── rpi4 │ └── default.nix ├── modules ├── sd-image │ ├── rpi3 │ │ └── default.nix │ ├── rpi4 │ │ └── default.nix │ ├── generic-aarch64 │ │ └── default.nix │ ├── rpizero │ │ ├── default.nix │ │ └── sd-image.nix │ └── rpizero2 │ │ ├── default.nix │ │ └── sd-image.nix ├── hardware │ ├── audio.nix │ ├── default.nix │ ├── kernel.nix │ ├── platform.nix │ ├── pkgs-overlays.nix │ ├── hifiberry-dac │ │ └── default.nix │ ├── hifiberry-dacplusdsp │ │ └── default.nix │ ├── spi0-1cs.nix │ ├── apply-overlays-dtmerge.nix │ ├── respeaker-4mic │ │ └── default.nix │ ├── respeaker-8mic │ │ └── default.nix │ ├── respeaker-2mic │ │ └── default.nix │ ├── hifiberry-dacplus │ │ └── default.nix │ └── hifiberry-dacplusadc │ │ └── default.nix └── base │ └── default.nix ├── packages ├── default.nix └── seeed-voicecard │ └── default.nix ├── .github ├── renovate.json5 └── lint │ └── .yamllint.yaml ├── Taskfile.yml ├── .pre-commit-config.yaml ├── LICENSE ├── flake.lock ├── flake.nix └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *result* 2 | -------------------------------------------------------------------------------- /overlays/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: { 7 | seeed-voicecard = pkgs.callPackage ./seeed-voicecard {}; 8 | } 9 | -------------------------------------------------------------------------------- /platforms/rpi3/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | lib, 5 | ... 6 | }: { 7 | imports = [ 8 | ../../modules/base 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /platforms/rpizero/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | lib, 5 | ... 6 | }: { 7 | imports = [ 8 | ../../modules/base 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /modules/sd-image/rpi3/default.nix: -------------------------------------------------------------------------------- 1 | {modulesPath, ...}: { 2 | imports = [ 3 | ../generic-aarch64 4 | ]; 5 | raspberry-pi.hardware.platform.type = "rpi3"; 6 | } 7 | -------------------------------------------------------------------------------- /packages/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs}: 2 | pkgs.lib.makeScope pkgs.newScope (self: let 3 | callPackage = self.callPackage; 4 | in { 5 | seeed-voicecard = callPackage ./seeed-voicecard {}; 6 | }) 7 | -------------------------------------------------------------------------------- /modules/sd-image/rpi4/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | modulesPath, 3 | lib, 4 | ... 5 | }: { 6 | imports = [ 7 | ../generic-aarch64 8 | ]; 9 | 10 | raspberry-pi.hardware.platform.type = lib.mkDefault "rpi4"; 11 | } 12 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "nix": { 4 | "enabled": true 5 | }, 6 | "lockFileMaintenance": { 7 | "enabled": true 8 | }, 9 | "extends": [ 10 | "config:recommended" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /modules/hardware/audio.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.audio; 8 | in { 9 | options.raspberry-pi.hardware.audio = { 10 | enable = lib.mkEnableOption '' 11 | Enable the default audio output of the Raspberry Pi. 12 | ''; 13 | }; 14 | config = lib.mkIf cfg.enable { 15 | boot.kernelParams = ["snd_bcm2835.enable_hdmi=1"]; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /modules/hardware/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: { 7 | imports = [ 8 | ./platform.nix 9 | ./kernel.nix 10 | ./pkgs-overlays.nix 11 | ./audio.nix 12 | ./hifiberry-dac 13 | ./hifiberry-dacplusadc 14 | ./hifiberry-dacplusdsp 15 | ./hifiberry-dacplus 16 | ./respeaker-8mic 17 | ./respeaker-4mic 18 | ./respeaker-2mic 19 | ./spi0-1cs.nix 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /platforms/rpizero2/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | lib, 5 | ... 6 | }: { 7 | imports = [ 8 | ../../modules/base 9 | ../../modules/hardware 10 | ]; 11 | raspberry-pi.hardware.platform.type = "rpizero2"; 12 | #raspberry-pi.hardware.hifiberry-dacplusadc.enable = true; 13 | #raspberry-pi.hardware.respeaker-8mic.enable = true; 14 | #raspberry-pi.hardware.respeaker-4mic.enable = true; 15 | #raspberry-pi.hardware.respeaker-2mic.enable = true; 16 | } 17 | -------------------------------------------------------------------------------- /.github/lint/.yamllint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: | 3 | .direnv/ 4 | .private/ 5 | .vscode/ 6 | 7 | extends: default 8 | 9 | rules: 10 | truthy: 11 | allowed-values: ["true", "false", "on"] 12 | 13 | comments: 14 | min-spaces-from-content: 1 15 | 16 | line-length: disable 17 | 18 | braces: 19 | min-spaces-inside: 0 20 | max-spaces-inside: 1 21 | 22 | brackets: 23 | min-spaces-inside: 0 24 | max-spaces-inside: 0 25 | 26 | indentation: enable 27 | -------------------------------------------------------------------------------- /modules/sd-image/generic-aarch64/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | modulesPath, 3 | config, 4 | lib, 5 | pkgs, 6 | ... 7 | }: { 8 | imports = [ 9 | (modulesPath + "/installer/sd-card/sd-image-aarch64-installer.nix") 10 | ../../base 11 | ]; 12 | sdImage = { 13 | # bzip2 compression takes loads of time with emulation, skip it. Enable this if you're low on space. 14 | compressImage = lib.mkDefault false; 15 | }; 16 | hardware.enableRedistributableFirmware = true; 17 | } 18 | -------------------------------------------------------------------------------- /modules/hardware/kernel.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | platformType = config.raspberry-pi.hardware.platform.type; 8 | in { 9 | #boot.kernelPackages = 10 | # if platformType == "rpi3" 11 | # then lib.mkOverride 1499 pkgs.linuxPackages_rpi3 12 | # else if platformType == "rpi4" 13 | # then lib.mkForce pkgs.linuxPackages_rpi4 14 | # else if platformType == "rpizero2" 15 | # then lib.mkForce pkgs.linuxPackages 16 | # else pkgs.linuxPackages_latest; 17 | } 18 | -------------------------------------------------------------------------------- /platforms/rpi4/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | lib, 5 | ... 6 | }: { 7 | imports = [ 8 | ../../modules/base 9 | ../../modules/hardware 10 | ]; 11 | raspberry-pi.hardware.platform.type = "rpi4"; 12 | # Also increase the amount of CMA to ensure the virtual console on the RPi4 works. 13 | boot.kernelParams = ["cma=128M" "console=tty0"]; 14 | raspberry-pi.hardware.hifiberry-dacplusadc.enable = true; 15 | raspberry-pi.hardware.respeaker-8mic.enable = true; 16 | raspberry-pi.hardware.respeaker-4mic.enable = true; 17 | raspberry-pi.hardware.respeaker-2mic.enable = true; 18 | } 19 | -------------------------------------------------------------------------------- /modules/sd-image/rpizero/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | modulesPath, 6 | ... 7 | }: { 8 | imports = [ 9 | (modulesPath + "/installer/sd-card/sd-image-raspberrypi-installer.nix") 10 | ./sd-image.nix 11 | ]; 12 | 13 | sdImage = { 14 | # Pi Zero struggles to work without swap 15 | swap.enable = true; 16 | swap.size = 1024; 17 | extraFirmwareConfig = { 18 | # Give up VRAM for more Free System Memory 19 | # - Disable camera which automatically reserves 128MB VRAM 20 | start_x = 0; 21 | # - Reduce allocation of VRAM to 16MB minimum for non-rotated (32MB for rotated) 22 | gpu_mem = 16; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/sd-image/rpizero2/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | modulesPath, 6 | ... 7 | }: { 8 | imports = [ 9 | ../generic-aarch64 10 | ./sd-image.nix 11 | ]; 12 | 13 | raspberry-pi.hardware.platform.type = "rpizero2"; 14 | sdImage = { 15 | # Pi Zero 2 struggles to work without swap 16 | swap.enable = true; 17 | swap.size = 1024; 18 | extraFirmwareConfig = { 19 | # Give up VRAM for more Free System Memory 20 | # - Disable camera which automatically reserves 128MB VRAM 21 | start_x = 0; 22 | # - Reduce allocation of VRAM to 16MB minimum for non-rotated (32MB for rotated) 23 | gpu_mem = 16; 24 | }; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | #env: 5 | 6 | includes: 7 | 8 | tasks: 9 | default: 10 | silent: true 11 | cmds: 12 | - task -l 13 | 14 | check: 15 | desc: Check the flake 16 | cmds: 17 | - nix flake check --all-systems 18 | 19 | update: 20 | desc: Update the flake inputs 21 | cmds: 22 | - nix flake update 23 | 24 | sd-image:rpi4: 25 | desc: Build the SD Card Image for the Raspberry Pi 4 26 | cmds: 27 | - nix build .#images.rpi4 28 | 29 | sd-image:rpi3: 30 | desc: Build the SD Card Image for the Raspberry Pi 3 31 | cmds: 32 | - nix build .#images.rpi3 33 | 34 | sd-image:rpizero2: 35 | desc: Build the SD Card Image for the Raspberry Pi Zero W 2 36 | cmds: 37 | - nix build .#images.rpizero2 38 | 39 | sd-image:rpizero: 40 | desc: Build the SD Card Image for the Raspberry Pi Zero W 41 | cmds: 42 | - nix build .#images.rpizero 43 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fail_fast: false 3 | 4 | repos: 5 | - repo: https://github.com/kamadorueda/alejandra 6 | rev: 3.0.0 7 | hooks: 8 | - id: alejandra-system 9 | 10 | - repo: https://github.com/adrienverge/yamllint 11 | rev: v1.32.0 12 | hooks: 13 | - args: 14 | - --config-file 15 | - .github/lint/.yamllint.yaml 16 | id: yamllint 17 | - repo: https://github.com/pre-commit/pre-commit-hooks 18 | rev: v4.4.0 19 | hooks: 20 | - id: trailing-whitespace 21 | - id: end-of-file-fixer 22 | - id: fix-byte-order-marker 23 | - id: mixed-line-ending 24 | - id: check-added-large-files 25 | args: [--maxkb=2048] 26 | - id: check-merge-conflict 27 | - id: check-executables-have-shebangs 28 | - repo: https://github.com/Lucas-C/pre-commit-hooks 29 | rev: v1.5.4 30 | hooks: 31 | - id: remove-crlf 32 | - id: remove-tabs 33 | exclude: (Makefile) 34 | -------------------------------------------------------------------------------- /modules/hardware/platform.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.platform; 8 | in { 9 | options.raspberry-pi.hardware.platform = { 10 | type = lib.mkOption { 11 | type = lib.types.enum ["rpi3" "rpi4" "rpizero2"]; 12 | default = null; 13 | description = lib.mdDoc '' 14 | The Raspberry Pi Platform the build is targeting. 15 | ''; 16 | }; 17 | deviceTreeFilter = lib.mkOption { 18 | type = lib.types.str; 19 | default = null; 20 | description = lib.mdDoc '' 21 | A string to filter the device tree files by. 22 | ''; 23 | }; 24 | }; 25 | config = { 26 | raspberry-pi.hardware.platform.deviceTreeFilter = 27 | if cfg.type == "rpi4" 28 | then "bcm2711-rpi-4*.dtb" 29 | else if cfg.type == "rpi3" 30 | then "bcm*-rpi-3-*.dtb" 31 | else if cfg.type == "rpizero2" 32 | then "bcm2837-rpi-zero-2-w.dtb" 33 | else ""; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Casey Link 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /modules/hardware/pkgs-overlays.nix: -------------------------------------------------------------------------------- 1 | # source: https://github.com/NixOS/nixos-hardware/blob/master/raspberry-pi/4/pkgs-overlays.nix 2 | # License: Creative Commons Zero v1.0 Universal 3 | { 4 | config, 5 | pkgs, 6 | lib, 7 | ... 8 | }: let 9 | cfg = config.raspberry-pi.hardware.apply-overlays-dtmerge; 10 | dt_ao_overlay = _final: prev: { 11 | deviceTree = 12 | prev.deviceTree 13 | // { 14 | applyOverlays = _final.callPackage ./apply-overlays-dtmerge.nix {}; 15 | }; 16 | }; 17 | in { 18 | options.raspberry-pi.hardware.apply-overlays-dtmerge = { 19 | enable = lib.mkEnableOption '' 20 | replace deviceTree.applyOverlays implementation to use dtmerge from libraspberrypi. 21 | this can resolve issues with applying dtbs for the pi. 22 | ''; 23 | }; 24 | 25 | config = lib.mkIf cfg.enable { 26 | nixpkgs.overlays = [dt_ao_overlay]; 27 | hardware = { 28 | firmware = [pkgs.wireless-regdb]; 29 | i2c.enable = true; 30 | deviceTree = { 31 | enable = true; 32 | filter = config.raspberry-pi.hardware.platform.deviceTreeFilter; 33 | }; 34 | }; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixos-hardware": { 4 | "locked": { 5 | "lastModified": 1710123225, 6 | "narHash": "sha256-j3oWlxRZxB7cFsgEntpH3rosjFHRkAo/dhX9H3OfxtY=", 7 | "owner": "nixos", 8 | "repo": "nixos-hardware", 9 | "rev": "ad2fd7b978d5e462048729a6c635c45d3d33c9ba", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "repo": "nixos-hardware", 15 | "type": "github" 16 | } 17 | }, 18 | "nixpkgs": { 19 | "locked": { 20 | "lastModified": 1710451336, 21 | "narHash": "sha256-pP86Pcfu3BrAvRO7R64x7hs+GaQrjFes+mEPowCfkxY=", 22 | "owner": "nixos", 23 | "repo": "nixpkgs", 24 | "rev": "d691274a972b3165335d261cc4671335f5c67de9", 25 | "type": "github" 26 | }, 27 | "original": { 28 | "owner": "nixos", 29 | "ref": "nixos-unstable", 30 | "repo": "nixpkgs", 31 | "type": "github" 32 | } 33 | }, 34 | "root": { 35 | "inputs": { 36 | "nixos-hardware": "nixos-hardware", 37 | "nixpkgs": "nixpkgs" 38 | } 39 | } 40 | }, 41 | "root": "root", 42 | "version": 7 43 | } 44 | -------------------------------------------------------------------------------- /packages/seeed-voicecard/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | lib, 4 | fetchFromGitHub, 5 | fetchpatch, 6 | kernel, 7 | ... 8 | }: 9 | pkgs.stdenv.mkDerivation rec { 10 | name = "seeed-voicecard-${version}-module-${kernel.modDirVersion}"; 11 | version = "v4.1-post"; 12 | 13 | src = fetchFromGitHub { 14 | owner = "HinTak"; 15 | repo = "seeed-voicecard"; 16 | rev = "4ab8158c18047e2c6d01e46958e3c1cb34f4983a"; 17 | hash = "sha256-TOh6mexfU4qI4LuR3Q5W6s2o74DInSSrj1CnKV51qOg="; 18 | }; 19 | 20 | #preConfigure = '' 21 | # substituteInPlace Makefile --replace "snd-soc-wm8960-objs := wm8960.o" "" 22 | # substituteInPlace Makefile --replace "obj-m += snd-soc-wm8960.o" "" 23 | #''; 24 | 25 | KERNELDIR = "${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"; 26 | 27 | NIX_CFLAGS = ["-Wno-error=cpp"]; 28 | 29 | nativeBuildInputs = [pkgs.perl] ++ kernel.moduleBuildDependencies; 30 | buildInputs = [pkgs.alsa-lib]; 31 | 32 | buildPhase = '' 33 | make -C $KERNELDIR M=$(pwd) modules 34 | make -C ac108_plugin libasound_module_pcm_ac108.so 35 | sed -i "s/brcm,bcm2708/raspberrypi/" *.dts 36 | ''; 37 | installPhase = '' 38 | mkdir -p $out/lib/modules/${kernel.modDirVersion}/sound/soc/codecs 39 | mkdir -p $out/lib/modules/${kernel.modDirVersion}/sound/soc/bcm 40 | cp snd-soc-wm8960.ko $out/lib/modules/${kernel.modDirVersion}/sound/soc/codecs 41 | cp snd-soc-ac108.ko $out/lib/modules/${kernel.modDirVersion}/sound/soc/codecs 42 | cp snd-soc-seeed-voicecard.ko $out/lib/modules/${kernel.modDirVersion}/sound/soc/bcm 43 | mkdir $out/lib/dts $out/lib/alsa-lib 44 | cp *.dts $out/lib/dts 45 | cp ac108_plugin/libasound_module_pcm_ac108.so $out/lib/alsa-lib 46 | 47 | ''; 48 | } 49 | -------------------------------------------------------------------------------- /modules/hardware/hifiberry-dac/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.hifiberry-dac; 8 | in { 9 | options.raspberry-pi.hardware.hifiberry-dac = { 10 | enable = lib.mkEnableOption '' 11 | support for the Raspberry Pi Hifiberry HATs: DAC+ Light/DAC Zero/MiniAmp/Beocreate/DAC+ DSP/DAC+ RTC 12 | ''; 13 | }; 14 | config = lib.mkIf cfg.enable { 15 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 16 | hardware.deviceTree = { 17 | overlays = [ 18 | # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-6.6.y/arch/arm/boot/dts/overlays/hifiberry-dac-overlay.dts 19 | # 20 | # changes 21 | # - modified top-level "compatible" field from bcm2835 to bcm2711 22 | # - s/i2s_clk_producer/i2s/ (name on bcm2711 platform) 23 | { 24 | name = "hifiberry-dac"; 25 | dtsText = '' 26 | // Definitions for HiFiBerry DAC 27 | /dts-v1/; 28 | /plugin/; 29 | 30 | / { 31 | compatible = "brcm,bcm2711"; 32 | 33 | fragment@0 { 34 | target = <&i2s>; 35 | __overlay__ { 36 | status = "okay"; 37 | }; 38 | }; 39 | 40 | fragment@1 { 41 | target-path = "/"; 42 | __overlay__ { 43 | pcm5102a-codec { 44 | #sound-dai-cells = <0>; 45 | compatible = "ti,pcm5102a"; 46 | status = "okay"; 47 | }; 48 | }; 49 | }; 50 | 51 | fragment@2 { 52 | target = <&sound>; 53 | __overlay__ { 54 | compatible = "hifiberry,hifiberry-dac"; 55 | i2s-controller = <&i2s>; 56 | status = "okay"; 57 | }; 58 | }; 59 | }; 60 | ''; 61 | } 62 | ]; 63 | }; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /modules/hardware/hifiberry-dacplusdsp/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.hifiberry-dacplusdsp; 8 | in { 9 | options.raspberry-pi.hardware.hifiberry-dacplusdsp = { 10 | enable = lib.mkEnableOption '' 11 | support for the Raspberry Pi Hifiberry DAC + DSP HAT. 12 | ''; 13 | }; 14 | config = lib.mkIf cfg.enable { 15 | assertions = [ 16 | { 17 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 18 | message = "The Hifiberry DAC+ DSP HAT is not compatible with the Raspberry Pi Zero 2."; 19 | } 20 | ]; 21 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 22 | hardware.deviceTree = { 23 | overlays = [ 24 | # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/hifiberry-dacplusdsp-overlay.dts 25 | # but compatible changed from bcm2835 to bcm2711 26 | { 27 | name = "hifiberry-dacplusdsp"; 28 | dtsText = '' 29 | // Definitions for hifiberry DAC+DSP soundcard overlay 30 | /dts-v1/; 31 | /plugin/; 32 | 33 | / { 34 | compatible = "brcm,bcm2711"; 35 | 36 | fragment@0 { 37 | target = <&i2s>; 38 | __overlay__ { 39 | status = "okay"; 40 | }; 41 | }; 42 | 43 | fragment@1 { 44 | target-path = "/"; 45 | __overlay__ { 46 | dacplusdsp-codec { 47 | #sound-dai-cells = <0>; 48 | compatible = "hifiberry,dacplusdsp"; 49 | status = "okay"; 50 | }; 51 | }; 52 | }; 53 | 54 | fragment@2 { 55 | target = <&sound>; 56 | __overlay__ { 57 | compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard"; 58 | i2s-controller = <&i2s>; 59 | status = "okay"; 60 | }; 61 | }; 62 | }; 63 | ''; 64 | } 65 | ]; 66 | }; 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /modules/hardware/spi0-1cs.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.spi0-1cs; 8 | in { 9 | options.raspberry-pi.hardware.spi0-1cs = { 10 | enable = 11 | lib.mkEnableOption '' 12 | ''; 13 | cs0_pin = lib.mkOption { 14 | type = lib.types.int; 15 | default = 8; 16 | description = "CS0 pin number for SPI0."; 17 | }; 18 | }; 19 | config = lib.mkIf cfg.enable { 20 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 21 | hardware.deviceTree = { 22 | overlays = [ 23 | # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-6.6.y/arch/arm/boot/dts/overlays/spi0-1cs-overlay.dts 24 | # but compatible changed from bcm2835 to bcm2711 25 | { 26 | name = "spi0-1cs-overlay"; 27 | dtsText = let 28 | cs0_pin_value = toString cfg.cs0_pin; 29 | in '' 30 | /dts-v1/; 31 | /plugin/; 32 | 33 | 34 | / { 35 | compatible = "brcm,bcm2711"; 36 | 37 | fragment@0 { 38 | target = <&spi0_cs_pins>; 39 | frag0: __overlay__ { 40 | brcm,pins = <${cs0_pin_value}>; 41 | }; 42 | }; 43 | 44 | fragment@1 { 45 | target = <&spi0>; 46 | frag1: __overlay__ { 47 | cs-gpios = <&gpio ${cs0_pin_value} 1>; 48 | status = "okay"; 49 | }; 50 | }; 51 | 52 | fragment@2 { 53 | target = <&spidev1>; 54 | __overlay__ { 55 | status = "disabled"; 56 | }; 57 | }; 58 | 59 | fragment@3 { 60 | target = <&spi0_pins>; 61 | __dormant__ { 62 | brcm,pins = <10 11>; 63 | }; 64 | }; 65 | 66 | __overrides__ { 67 | cs0_pin = <&frag0>,"brcm,pins:0", 68 | <&frag1>,"cs-gpios:4"; 69 | no_miso = <0>,"=3"; 70 | }; 71 | }; 72 | ''; 73 | } 74 | ]; 75 | }; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 4 | nixos-hardware.url = "github:nixos/nixos-hardware"; 5 | }; 6 | outputs = { 7 | self, 8 | nixpkgs, 9 | nixos-hardware, 10 | }: { 11 | nixosModules = { 12 | sd-image-rpizero2 = import ./modules/sd-image/rpizero2; 13 | sd-image-rpi3 = import ./modules/sd-image/rpi3; 14 | sd-image-rpi4 = import ./modules/sd-image/rpi4; 15 | hardware = import ./modules/hardware; 16 | base = import ./modules/base; 17 | }; 18 | images = { 19 | rpi4 = 20 | (self.nixosConfigurations.rpi4.extendModules { 21 | modules = [./modules/sd-image/rpi4]; 22 | }) 23 | .config 24 | .system 25 | .build 26 | .sdImage; 27 | rpi3 = 28 | (self.nixosConfigurations.rpi3.extendModules { 29 | modules = [./modules/sd-image/rpi3]; 30 | }) 31 | .config 32 | .system 33 | .build 34 | .sdImage; 35 | rpizero2 = 36 | (self.nixosConfigurations.rpizero2.extendModules { 37 | modules = [./modules/sd-image/rpizero2]; 38 | }) 39 | .config 40 | .system 41 | .build 42 | .sdImage; 43 | rpizero = 44 | (self.nixosConfigurations.rpizero.extendModules { 45 | modules = [./modules/sd-image/rpizero]; 46 | }) 47 | .config 48 | .system 49 | .build 50 | .sdImage; 51 | }; 52 | nixosConfigurations = { 53 | rpi4 = nixpkgs.lib.nixosSystem { 54 | system = "aarch64-linux"; 55 | modules = [ 56 | nixos-hardware.nixosModules.raspberry-pi-4 57 | ./platforms/rpi4 58 | ]; 59 | }; 60 | rpi3 = nixpkgs.lib.nixosSystem { 61 | system = "aarch64-linux"; 62 | modules = [ 63 | nixos-hardware.nixosModules.raspberry-pi-4 64 | ./platforms/rpi3 65 | ]; 66 | }; 67 | rpizero2 = nixpkgs.lib.nixosSystem { 68 | system = "aarch64-linux"; 69 | modules = [ 70 | nixos-hardware.nixosModules.raspberry-pi-4 71 | ./platforms/rpizero2 72 | ]; 73 | }; 74 | 75 | rpizero = nixpkgs.lib.nixosSystem { 76 | system = "armv6l-linux"; 77 | modules = [ 78 | nixos-hardware.nixosModules.raspberry-pi-4 79 | ./platforms/rpizero 80 | ]; 81 | }; 82 | }; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /modules/hardware/apply-overlays-dtmerge.nix: -------------------------------------------------------------------------------- 1 | # source: https://github.com/NixOS/nixos-hardware/blob/master/raspberry-pi/4/apply-overlays-dtmerge.nix 2 | # License: Creative Commons Zero v1.0 Universal 3 | # modification of nixpkgs deviceTree.applyOverlays to resolve https://github.com/NixOS/nixpkgs/issues/125354 4 | # derived from https://github.com/NixOS/nixpkgs/blob/916ca8f2b0c208def051f8ea9760c534a40309db/pkgs/os-specific/linux/device-tree/default.nix 5 | { 6 | lib, 7 | stdenvNoCC, 8 | dtc, 9 | libraspberrypi, 10 | }: 11 | with lib; (base: overlays': 12 | stdenvNoCC.mkDerivation { 13 | name = "device-tree-overlays"; 14 | nativeBuildInputs = [dtc libraspberrypi]; 15 | buildCommand = let 16 | overlays = toList overlays'; 17 | in '' 18 | mkdir -p $out 19 | cd "${base}" 20 | find . -type f -name '*.dtb' -print0 \ 21 | | xargs -0 cp -v --no-preserve=mode --target-directory "$out" --parents 22 | 23 | for dtb in $(find "$out" -type f -name '*.dtb'); do 24 | dtbCompat=$(fdtget -t s "$dtb" / compatible 2>/dev/null || true) 25 | # skip files without `compatible` string 26 | test -z "$dtbCompat" && continue 27 | 28 | ${flip (concatMapStringsSep "\n") overlays (o: '' 29 | overlayCompat="$(fdtget -t s "${o.dtboFile}" / compatible)" 30 | 31 | # skip incompatible and non-matching overlays 32 | if [[ ! "$dtbCompat" =~ "$overlayCompat" ]] && [[ ! "$overlayCompat" =~ "hifiberry" ]]; then 33 | echo "$dtbCompat" $overlayCompat 34 | echo "Skipping overlay ${o.name}: incompatible with $(basename "$dtb")" 35 | elif ${ 36 | if ((o.filter or null) == null) 37 | then "false" 38 | else '' 39 | [[ "''${dtb//${o.filter}/}" == "$dtb" ]] 40 | '' 41 | } 42 | then 43 | echo "Skipping overlay ${o.name}: filter does not match $(basename "$dtb")" 44 | else 45 | echo "$dtbCompat" $overlayCompat 46 | echo -n "Applying overlay ${o.name} to $(basename "$dtb")... " 47 | mv "$dtb"{,.in} 48 | 49 | # dtmerge requires a .dtbo ext for dtbo files, otherwise it adds it to the given file implicitly 50 | dtboWithExt="$TMPDIR/$(basename "${o.dtboFile}").dtbo" 51 | cp -r ${o.dtboFile} "$dtboWithExt" 52 | 53 | dtmerge "$dtb.in" "$dtb" "$dtboWithExt" 54 | 55 | echo "ok" 56 | rm "$dtb.in" "$dtboWithExt" 57 | fi 58 | '')} 59 | 60 | done''; 61 | }) 62 | -------------------------------------------------------------------------------- /modules/hardware/respeaker-4mic/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.respeaker-4mic; 8 | seeed-voicecard = pkgs.callPackage ../../../packages/seeed-voicecard {kernel = config.boot.kernelPackages.kernel;}; 9 | in { 10 | options.raspberry-pi.hardware.respeaker-4mic = { 11 | enable = lib.mkEnableOption '' 12 | support for the Seeed Studio ReSpeaker 4-Mic Array for Raspberry Pi 13 | ''; 14 | }; 15 | config = lib.mkIf cfg.enable { 16 | assertions = [ 17 | { 18 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 19 | message = "The ReSpeaker 4-Mic Array is not compatible with the Raspberry Pi Zero 2."; 20 | } 21 | ]; 22 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 23 | hardware.deviceTree = { 24 | enable = true; 25 | overlays = [ 26 | { 27 | name = "respeaker-4mic"; 28 | dtsFile = "${seeed-voicecard}/lib/dts/seeed-4mic-voicecard-overlay.dts"; 29 | } 30 | { 31 | name = "spi"; 32 | dtsText = '' 33 | /dts-v1/; 34 | /plugin/; 35 | 36 | / { 37 | compatible = "raspberrypi"; 38 | fragment@0 { 39 | target = <&spi>; 40 | __overlay__ { 41 | cs-gpios = <&gpio 8 1>, <&gpio 7 1>; 42 | status = "okay"; 43 | pinctrl-names = "default"; 44 | pinctrl-0 = <&spi0_pins &spi0_cs_pins>; 45 | #address-cells = <1>; 46 | #size-cells = <0>; 47 | spidev@0 { 48 | reg = <0>; // CE0 49 | spi-max-frequency = <500000>; 50 | compatible = "spidev"; 51 | }; 52 | 53 | spidev@1 { 54 | reg = <1>; // CE1 55 | spi-max-frequency = <500000>; 56 | compatible = "spidev"; 57 | }; 58 | }; 59 | }; 60 | fragment@1 { 61 | target = <&alt0>; 62 | __overlay__ { 63 | // Drop GPIO 7, SPI 8-11 64 | brcm,pins = <4 5>; 65 | }; 66 | }; 67 | 68 | fragment@2 { 69 | target = <&gpio>; 70 | __overlay__ { 71 | spi0_pins: spi0_pins { 72 | brcm,pins = <9 10 11>; 73 | brcm,function = <4>; // alt0 74 | }; 75 | spi0_cs_pins: spi0_cs_pins { 76 | brcm,pins = <8 7>; 77 | brcm,function = <1>; // out 78 | }; 79 | }; 80 | }; 81 | }; 82 | ''; 83 | } 84 | ]; 85 | }; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /modules/hardware/respeaker-8mic/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.respeaker-8mic; 8 | seeed-voicecard = pkgs.callPackage ../../../packages/seeed-voicecard {kernel = config.boot.kernelPackages.kernel;}; 9 | in { 10 | options.raspberry-pi.hardware.respeaker-8mic = { 11 | enable = lib.mkEnableOption '' 12 | support for the Seeed Studio ReSpeaker 8-Mic Array for Raspberry Pi 13 | ''; 14 | }; 15 | config = lib.mkIf cfg.enable { 16 | assertions = [ 17 | { 18 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 19 | message = "The ReSpeaker 8-Mic Array is not compatible with the Raspberry Pi Zero 2."; 20 | } 21 | ]; 22 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 23 | hardware.deviceTree = { 24 | enable = true; 25 | overlays = [ 26 | { 27 | name = "respeaker-8mic"; 28 | dtsFile = "${seeed-voicecard}/lib/dts/seeed-8mic-voicecard-overlay.dts"; 29 | } 30 | { 31 | name = "spi"; 32 | dtsText = '' 33 | /dts-v1/; 34 | /plugin/; 35 | 36 | / { 37 | compatible = "raspberrypi"; 38 | fragment@0 { 39 | target = <&spi>; 40 | __overlay__ { 41 | cs-gpios = <&gpio 8 1>, <&gpio 7 1>; 42 | status = "okay"; 43 | pinctrl-names = "default"; 44 | pinctrl-0 = <&spi0_pins &spi0_cs_pins>; 45 | #address-cells = <1>; 46 | #size-cells = <0>; 47 | spidev@0 { 48 | reg = <0>; // CE0 49 | spi-max-frequency = <500000>; 50 | compatible = "spidev"; 51 | }; 52 | 53 | spidev@1 { 54 | reg = <1>; // CE1 55 | spi-max-frequency = <500000>; 56 | compatible = "spidev"; 57 | }; 58 | }; 59 | }; 60 | fragment@1 { 61 | target = <&alt0>; 62 | __overlay__ { 63 | // Drop GPIO 7, SPI 8-11 64 | brcm,pins = <4 5>; 65 | }; 66 | }; 67 | 68 | fragment@2 { 69 | target = <&gpio>; 70 | __overlay__ { 71 | spi0_pins: spi0_pins { 72 | brcm,pins = <9 10 11>; 73 | brcm,function = <4>; // alt0 74 | }; 75 | spi0_cs_pins: spi0_cs_pins { 76 | brcm,pins = <8 7>; 77 | brcm,function = <1>; // out 78 | }; 79 | }; 80 | }; 81 | }; 82 | ''; 83 | } 84 | ]; 85 | }; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /modules/base/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | platformType = config.raspberry-pi.hardware.platform.type; 8 | in { 9 | imports = [ 10 | ../hardware/platform.nix 11 | ]; 12 | 13 | # "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" creates a 14 | # disk with this label on first boot. Therefore, we need to keep it. It is the 15 | # only information from the installer image that we need to keep persistent 16 | fileSystems."/" = { 17 | device = "/dev/disk/by-label/NIXOS_SD"; 18 | fsType = "ext4"; 19 | }; 20 | boot = { 21 | tmp.useTmpfs = true; 22 | loader = { 23 | generic-extlinux-compatible.enable = lib.mkDefault true; 24 | grub.enable = lib.mkDefault false; 25 | }; 26 | 27 | initrd.availableKernelModules = [ 28 | "usbhid" 29 | "usb_storage" 30 | "vc4" 31 | "pcie_brcmstb" # required for the pcie bus to work 32 | "reset-raspberrypi" # required for vl805 firmware to load 33 | ]; 34 | 35 | kernelParams = 36 | #["console=tty0"] 37 | [] 38 | ++ ( 39 | if platformType == "rpi3" 40 | then ["cma=32M"] 41 | else if platformType == "rpi4" 42 | then ["cma=128M"] 43 | else [] 44 | ); 45 | }; 46 | nix.settings = { 47 | experimental-features = lib.mkDefault "nix-command flakes"; 48 | trusted-users = ["root" "@wheel"]; 49 | }; 50 | hardware.enableRedistributableFirmware = true; 51 | services.timesyncd.enable = lib.mkDefault true; 52 | networking = { 53 | useDHCP = lib.mkDefault true; 54 | interfaces.eth0.useDHCP = lib.mkDefault true; 55 | hostName = lib.mkDefault platformType; 56 | }; 57 | 58 | # Source: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/sd-card/sd-image-aarch64-new-kernel-no-zfs-installer.nix 59 | # Makes `availableOn` fail for zfs, see . 60 | # This is a workaround since we cannot remove the `"zfs"` string from `supportedFilesystems`. 61 | # The proper fix would be to make `supportedFilesystems` an attrset with true/false which we 62 | # could then `lib.mkForce false` 63 | nixpkgs.overlays = [ 64 | (final: super: { 65 | zfs = super.zfs.overrideAttrs (_: { 66 | meta.platforms = []; 67 | }); 68 | }) 69 | 70 | # Workaround: https://github.com/NixOS/nixpkgs/issues/154163 71 | # modprobe: FATAL: Module sun4i-drm not found in directory 72 | (final: super: { 73 | makeModulesClosure = x: 74 | super.makeModulesClosure (x // {allowMissing = true;}); 75 | }) 76 | ]; 77 | 78 | # Trim some fat 79 | # This causes an overlay which causes a lot of rebuilding 80 | environment.noXlibs = lib.mkForce false; 81 | # Limit the journal size to X MB or last Y days of logs 82 | services.journald.extraConfig = '' 83 | SystemMaxUse=1536M 84 | MaxFileSec=60day 85 | ''; 86 | services.fwupd.enable = false; 87 | services.udisks2.enable = false; 88 | programs.command-not-found.enable = false; 89 | boot.enableContainers = false; 90 | } 91 | -------------------------------------------------------------------------------- /modules/hardware/respeaker-2mic/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.respeaker-2mic; 8 | seeed-voicecard = pkgs.callPackage ../../../packages/seeed-voicecard {kernel = config.boot.kernelPackages.kernel;}; 9 | in { 10 | options.raspberry-pi.hardware.respeaker-2mic = { 11 | enable = lib.mkEnableOption '' 12 | support for the Seeed Studio ReSpeaker 2-Mic Array for Raspberry Pi 13 | ''; 14 | }; 15 | config = lib.mkIf cfg.enable { 16 | assertions = [ 17 | { 18 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 19 | message = "The ReSpeaker 2-Mic Array is not compatible with the Raspberry Pi Zero 2."; 20 | } 21 | ]; 22 | boot.extraModulePackages = [ 23 | seeed-voicecard 24 | ]; 25 | hardware.raspberry-pi."4".i2c1.enable = true; 26 | boot.initrd.kernelModules = [ 27 | "snd-soc-seeed-voicecard" 28 | "snd-soc-ac108" 29 | "i2c-dev" 30 | "i2c-bcm2708" # was disabled 31 | "snd-soc-wm8960" # was disabled 32 | ]; 33 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 34 | hardware.deviceTree = { 35 | enable = true; 36 | overlays = [ 37 | { 38 | name = "respeaker-2mic"; 39 | dtsFile = "${seeed-voicecard}/lib/dts/seeed-2mic-voicecard-overlay.dts"; 40 | } 41 | { 42 | name = "spi"; 43 | dtsText = '' 44 | /dts-v1/; 45 | /plugin/; 46 | 47 | / { 48 | compatible = "raspberrypi"; 49 | fragment@0 { 50 | target = <&spi>; 51 | __overlay__ { 52 | cs-gpios = <&gpio 8 1>, <&gpio 7 1>; 53 | status = "okay"; 54 | pinctrl-names = "default"; 55 | pinctrl-0 = <&spi0_pins &spi0_cs_pins>; 56 | #address-cells = <1>; 57 | #size-cells = <0>; 58 | spidev@0 { 59 | reg = <0>; // CE0 60 | spi-max-frequency = <500000>; 61 | compatible = "spidev"; 62 | }; 63 | 64 | spidev@1 { 65 | reg = <1>; // CE1 66 | spi-max-frequency = <500000>; 67 | compatible = "spidev"; 68 | }; 69 | }; 70 | }; 71 | fragment@1 { 72 | target = <&alt0>; 73 | __overlay__ { 74 | // Drop GPIO 7, SPI 8-11 75 | brcm,pins = <4 5>; 76 | }; 77 | }; 78 | 79 | fragment@2 { 80 | target = <&gpio>; 81 | __overlay__ { 82 | spi0_pins: spi0_pins { 83 | brcm,pins = <9 10 11>; 84 | brcm,function = <4>; // alt0 85 | }; 86 | spi0_cs_pins: spi0_cs_pins { 87 | brcm,pins = <8 7>; 88 | brcm,function = <1>; // out 89 | }; 90 | }; 91 | }; 92 | }; 93 | ''; 94 | } 95 | ]; 96 | }; 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /modules/hardware/hifiberry-dacplus/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.hifiberry-dacplus; 8 | in { 9 | options.raspberry-pi.hardware.hifiberry-dacplus = { 10 | enable = lib.mkEnableOption '' 11 | support for the Raspberry Pi Hifiberry DAC + HAT. 12 | ''; 13 | }; 14 | config = lib.mkIf cfg.enable { 15 | assertions = [ 16 | { 17 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 18 | message = "The Hifiberry DAC+ HAT is not compatible with the Raspberry Pi Zero 2."; 19 | } 20 | ]; 21 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 22 | hardware.deviceTree = { 23 | overlays = [ 24 | # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts 25 | # but compatible changed from bcm2835 to bcm2711 26 | { 27 | name = "hifiberry-dacplus"; 28 | dtsText = '' 29 | // Definitions for HiFiBerry DAC+ 30 | /dts-v1/; 31 | /plugin/; 32 | 33 | / { 34 | compatible = "brcm,bcm2711"; 35 | 36 | fragment@0 { 37 | target-path = "/"; 38 | __overlay__ { 39 | dacpro_osc: dacpro_osc { 40 | compatible = "hifiberry,dacpro-clk"; 41 | #clock-cells = <0>; 42 | }; 43 | }; 44 | }; 45 | 46 | fragment@1 { 47 | target = <&i2s>; 48 | __overlay__ { 49 | status = "okay"; 50 | }; 51 | }; 52 | 53 | fragment@2 { 54 | target = <&i2c1>; 55 | __overlay__ { 56 | #address-cells = <1>; 57 | #size-cells = <0>; 58 | status = "okay"; 59 | 60 | pcm5122@4d { 61 | #sound-dai-cells = <0>; 62 | compatible = "ti,pcm5122"; 63 | reg = <0x4d>; 64 | clocks = <&dacpro_osc>; 65 | AVDD-supply = <&vdd_3v3_reg>; 66 | DVDD-supply = <&vdd_3v3_reg>; 67 | CPVDD-supply = <&vdd_3v3_reg>; 68 | status = "okay"; 69 | }; 70 | hpamp: hpamp@60 { 71 | compatible = "ti,tpa6130a2"; 72 | reg = <0x60>; 73 | status = "disabled"; 74 | }; 75 | }; 76 | }; 77 | 78 | fragment@3 { 79 | target = <&sound>; 80 | hifiberry_dacplus: __overlay__ { 81 | compatible = "hifiberry,hifiberry-dacplus"; 82 | i2s-controller = <&i2s>; 83 | status = "okay"; 84 | }; 85 | }; 86 | 87 | __overrides__ { 88 | 24db_digital_gain = 89 | <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?"; 90 | slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?"; 91 | leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?"; 92 | }; 93 | }; 94 | ''; 95 | } 96 | ]; 97 | }; 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /modules/hardware/hifiberry-dacplusadc/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.raspberry-pi.hardware.hifiberry-dacplusadc; 8 | in { 9 | options.raspberry-pi.hardware.hifiberry-dacplusadc = { 10 | enable = lib.mkEnableOption '' 11 | support for the Raspberry Pi Hifiberry DAC + ADC HAT. 12 | ''; 13 | }; 14 | config = lib.mkIf cfg.enable { 15 | assertions = [ 16 | { 17 | assertion = config.raspberry-pi.hardware.platform.type != "rpizero2"; 18 | message = "The Hifiberry DAC+ ADC HAT is not compatible with the Raspberry Pi Zero 2."; 19 | } 20 | ]; 21 | raspberry-pi.hardware.apply-overlays-dtmerge.enable = true; 22 | hardware.deviceTree = { 23 | overlays = [ 24 | # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts 25 | # but compatible changed from bcm2835 to bcm2711 26 | { 27 | name = "hifiberry-dacplusadc"; 28 | dtsText = '' 29 | // Definitions for HiFiBerry DAC+ADC 30 | /dts-v1/; 31 | /plugin/; 32 | 33 | / { 34 | compatible = "brcm,bcm2711"; 35 | 36 | fragment@0 { 37 | target-path = "/"; 38 | __overlay__ { 39 | dacpro_osc: dacpro_osc { 40 | compatible = "hifiberry,dacpro-clk"; 41 | #clock-cells = <0>; 42 | }; 43 | }; 44 | }; 45 | 46 | fragment@1 { 47 | target = <&i2s>; 48 | __overlay__ { 49 | status = "okay"; 50 | }; 51 | }; 52 | 53 | fragment@2 { 54 | target = <&i2c1>; 55 | __overlay__ { 56 | #address-cells = <1>; 57 | #size-cells = <0>; 58 | status = "okay"; 59 | 60 | pcm_codec: pcm5122@4d { 61 | #sound-dai-cells = <0>; 62 | compatible = "ti,pcm5122"; 63 | reg = <0x4d>; 64 | clocks = <&dacpro_osc>; 65 | AVDD-supply = <&vdd_3v3_reg>; 66 | DVDD-supply = <&vdd_3v3_reg>; 67 | CPVDD-supply = <&vdd_3v3_reg>; 68 | status = "okay"; 69 | }; 70 | }; 71 | }; 72 | 73 | fragment@3 { 74 | target-path = "/"; 75 | __overlay__ { 76 | dmic { 77 | #sound-dai-cells = <0>; 78 | compatible = "dmic-codec"; 79 | num-channels = <2>; 80 | status = "okay"; 81 | }; 82 | }; 83 | }; 84 | 85 | fragment@4 { 86 | target = <&sound>; 87 | hifiberry_dacplusadc: __overlay__ { 88 | compatible = "hifiberry,hifiberry-dacplusadc"; 89 | i2s-controller = <&i2s>; 90 | status = "okay"; 91 | }; 92 | }; 93 | 94 | __overrides__ { 95 | 24db_digital_gain = 96 | <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?"; 97 | slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?"; 98 | leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?"; 99 | }; 100 | }; 101 | ''; 102 | } 103 | ]; 104 | }; 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > Archive Note: I've archived this repo because I've moved away from using NixOS on Raspberry PIs 3 | > If you are only doing software on an RPI, NixOS works fine. But if you want 4 | > to use hardware (GPIO, HATs, etc) NixOS is a royal PITA and frankly not 5 | > worth the time to make it try and work. 6 | 7 | # NixOS on the Raspberry PI 8 | 9 | [![MIT Licensed](https://img.shields.io/github/license/ramblurr/nixos-raspberrypi)](./LICENSE) 10 | 11 | > A NixOS Flake providing bare bones (but ready to go!) configurations for Raspberry Pi devices. 12 | 13 | * Build sd-card images with your own configuration 14 | * Easily pull in fixes for various Raspberry Pi hardware variations and HATs 15 | 16 | 17 | ## Supported Hardware 18 | 19 | See the table below for a list of supported and unsupported hardware 20 | 21 | | Board | Arch | Supported | 22 | |-----------------------|---------|-----------| 23 | | Raspberry Pi 4 | aarch64 | Yes | 24 | | Raspberry Pi 3 | aarch64 | Yes | 25 | | Raspberry Pi Zero W 2 | aarch64 | Yes | 26 | | Raspberry Pi 2 | armv7 | No | 27 | | Raspberry Pi 1 | armv6 | No | 28 | | Raspberry Pi Zero W | armv6 | No | 29 | 30 | As you can tell only aarch64 is supported, this is because Nix provides public caches for this architecture. 31 | 32 | In theory it should be possible to build for non-aarch64 hardware, but there are 33 | no publicly available caches and the author hasn't yet tried to build them 34 | (though I do have several RPI 1s and RPI0W1s lying around...). 35 | 36 | [Read more about ARM on NixOS.](https://nixos.wiki/wiki/NixOS_on_ARM#Binary_cache) 37 | 38 | 39 | ## Workaround and other Shenanigans 40 | 41 | This repo provides workarounds for the following issues: 42 | 43 | - [Aarch64 SD images missing pi-zero-2.dtb file require to boot](https://github.com/NixOS/nixpkgs/issues/216886) 44 | - [modprobe: FATAL: Module sun4i-drm not found in directory](https://github.com/NixOS/nixpkgs/issues/154163) 45 | - [Raspberry Pi device tree overlays do not apply on 21.05 (or later)](https://github.com/NixOS/nixpkgs/issues/125354) 46 | 47 | ## Prerequisites 48 | 49 | * You are already running NixOS on your build machine 50 | 51 | If your build-machine isn't aarch64-linux, then you will need to add the 52 | following to your build machine's NixOS configuration to emulate aarch64 (arm64) 53 | so you can cross-build. 54 | 55 | ```nix 56 | { 57 | boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; 58 | } 59 | ``` 60 | 61 | ## Example Usage 62 | 63 | Using this flake you can create Raspberry PI SD card images with your own configuration. 64 | 65 |
66 | Example flake.nix (click me) 67 | 68 | ```nix 69 | # flake.nix 70 | { 71 | inputs = { 72 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 73 | nixos-raspberrypi.url = "github:ramblurr/nixos-raspberrypi"; 74 | }; 75 | outputs = { 76 | self, 77 | nixpkgs, 78 | nixos-raspberrypi, 79 | }: { 80 | images = { 81 | rpi4 = 82 | (nixos-raspberrypi.nixosConfigurations.rpi4.extendModules { 83 | modules = [ 84 | nixos-raspberrypi.nixosModules.sd-image-rpi4 85 | ./configuration.nix # <--- put your configuration here, see below for an example 86 | ]; 87 | }) 88 | .config 89 | .system 90 | .build 91 | .sdImage; 92 | }; 93 | }; 94 | } 95 | 96 | ``` 97 |
98 | 99 |
100 | Example configuration.nix (click me) 101 | 102 | 103 | ```nix 104 | # configuration.nix 105 | { pkgs, config, lib, ... }: 106 | { 107 | system.stateVersion = "23.11"; 108 | environment.systemPackages = with pkgs; [ vim git ]; 109 | services.openssh.enable = true; 110 | networking.hostName = "pi"; 111 | users = { 112 | users.YOUR_USERNAME = { 113 | password = "YOUR_PASSWORD"; 114 | isNormalUser = true; 115 | extraGroups = [ "wheel" ]; 116 | }; 117 | }; 118 | networking = { 119 | interfaces."wlan0".useDHCP = true; 120 | wireless = { 121 | interfaces = [ "wlan0" ]; 122 | enable = true; 123 | networks = { 124 | "YOUR_WIFI_SSID".psk = "YOUR_WIFI_PASSWORD"; 125 | }; 126 | }; 127 | }; 128 | } 129 | ``` 130 | 131 |
132 | 133 | Then run `nix build .#images.rpi4`. After a while your sd-image will appear in `result/sd-image/nixos-sd-image*.img` 134 | 135 | Some things to keep in mind for your config: 136 | 137 | * Don't forget to add a `system.stateVersion` do your configuration. 138 | * If you have a wifi only pi (e.g., Raspberry Pi Zero W 2), don't forget to configure the wireless network. 139 | 140 | ## List of Options 141 | 142 | | Module | Purpose | 143 | |-------------------------------------------------------------|---------------------------------------------------| 144 | | `raspberry-pi.hardware.hifiberry-dacplusadc.enable = true;` | Enable support for the Hifiberry DAC+ ADC | 145 | | `raspberry-pi.hardware.respeaker-2mic.enable = true;` | Enable support for the Seeed Respeaker 2 Mic card | 146 | | `raspberry-pi.hardware.respeaker-4mic.enable = true;` | Enable support for the Seeed Respeaker 4 Mic card | 147 | | `raspberry-pi.hardware.respeaker-8mic.enable = true;` | Enable support for the Seeed Respeaker 8 Mic card | 148 | 149 | # License 150 | 151 | Copyright (c) 2023 Casey Link. This flake is made available under the [MIT License](./LICENSE) (just like NixOS). 152 | -------------------------------------------------------------------------------- /modules/sd-image/rpizero/sd-image.nix: -------------------------------------------------------------------------------- 1 | # This module extends the official sd-image.nix with the following: 2 | # - ability to add a swap partition to the built image 3 | # - ability to add options to the config.txt firmware 4 | # - fix the uboot bug with pi zero 2 5 | # Related issue: https://github.com/NixOS/nixpkgs/issues/216886 6 | # Original file: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/sd-card/sd-image.nix 7 | { 8 | nixpkgs, 9 | config, 10 | lib, 11 | pkgs, 12 | ... 13 | }: 14 | with lib; let 15 | rootfsImage = pkgs.callPackage "${pkgs.path}/nixos/lib/make-ext4-fs.nix" ({ 16 | inherit (config.sdImage) storePaths; 17 | compressImage = config.sdImage.compressImage; 18 | populateImageCommands = config.sdImage.populateRootCommands; 19 | volumeLabel = "NIXOS_SD"; 20 | } 21 | // optionalAttrs (config.sdImage.rootPartitionUUID != null) { 22 | uuid = config.sdImage.rootPartitionUUID; 23 | }); 24 | in { 25 | options.sdImage = { 26 | swap = { 27 | enable = mkEnableOption "Create a swap partition."; 28 | partitionName = mkOption { 29 | type = types.str; 30 | default = "SWAP"; 31 | description = lib.mdDoc '' 32 | Name of the partition which holds the swap. 33 | ''; 34 | }; 35 | size = mkOption { 36 | type = types.int; 37 | default = 2 * 1024; 38 | description = lib.mdDoc '' 39 | Size of the swap partition, in megabytes. 40 | ''; 41 | }; 42 | }; 43 | 44 | extraFirmwareConfig = mkOption { 45 | type = types.attrs; 46 | default = {}; 47 | description = lib.mdDoc '' 48 | Extra configuration to be added to config.txt. 49 | ''; 50 | }; 51 | }; 52 | 53 | config = { 54 | # Override of the sd image build to optionally add a swap partition 55 | system.build.sdImage = lib.mkForce (pkgs.callPackage 56 | ({ 57 | stdenv, 58 | dosfstools, 59 | e2fsprogs, 60 | mtools, 61 | libfaketime, 62 | util-linux, 63 | zstd, 64 | }: 65 | stdenv.mkDerivation { 66 | name = config.sdImage.imageName; 67 | 68 | nativeBuildInputs = 69 | [dosfstools e2fsprogs libfaketime mtools util-linux] 70 | ++ lib.optional config.sdImage.compressImage zstd; 71 | 72 | inherit (config.sdImage) imageName compressImage; 73 | 74 | buildCommand = '' 75 | mkdir -p $out/nix-support $out/sd-image 76 | export img=$out/sd-image/${config.sdImage.imageName} 77 | 78 | echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system 79 | if test -n "$compressImage"; then 80 | echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products 81 | else 82 | echo "file sd-image $img" >> $out/nix-support/hydra-build-products 83 | fi 84 | 85 | root_fs=${rootfsImage} 86 | ${lib.optionalString config.sdImage.compressImage '' 87 | root_fs=./root-fs.img 88 | echo "Decompressing rootfs image" 89 | zstd -d --no-progress "${rootfsImage}" -o $root_fs 90 | ''} 91 | 92 | # Set swap size. Set it to 0 it swap is disabled. 93 | swapSize=${toString ( 94 | if config.sdImage.swap.enable 95 | then config.sdImage.swap.size 96 | else 0 97 | )} 98 | # The root partition is #2 if there is no swap, but is #3 is there is one 99 | rootPartitionNumber=${toString ( 100 | if config.sdImage.swap.enable 101 | then 3 102 | else 2 103 | )} 104 | 105 | # Gap in front of the first partition, in MiB 106 | gap=${toString config.sdImage.firmwarePartitionOffset} 107 | 108 | # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. 109 | rootSizeBlocks=$(du -B 512 --apparent-size $root_fs | awk '{ print $1 }') 110 | firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) 111 | # Note: swap size is 0 if swap is disabled 112 | imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024 + swapSize * 1024 * 1024)) 113 | truncate -s $imageSize $img 114 | 115 | # type=b is 'W95 FAT32', type=82 is 'Linux swap / Solaris', type=83 is 'Linux'. 116 | # The "bootable" partition is where u-boot will look file for the bootloader 117 | # information (dtbs, extlinux.conf file). 118 | 119 | sfdisk $img < 0) 185 | ( 186 | let 187 | # Convert the set into a string of lines of "key=value" pairs. 188 | keyValueMap = name: value: name + "=" + toString value; 189 | keyValueList = lib.mapAttrsToList keyValueMap config.sdImage.extraFirmwareConfig; 190 | extraFirmwareConfigString = lib.concatStringsSep "\n" keyValueList; 191 | in 192 | lib.mkAfter 193 | '' 194 | config=firmware/config.txt 195 | # The initial file has just been created without write permissions. Add them to be able to append the file. 196 | chmod u+w $config 197 | echo "\n# Extra configuration" >> $config 198 | echo "${extraFirmwareConfigString}" >> $config 199 | chmod u-w $config 200 | '' 201 | ); 202 | 203 | # Ugly hack to make it work with Pi Zero W 204 | sdImage.populateRootCommands = lib.mkForce '' 205 | mkdir -p ./files/boot 206 | ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot 207 | DTBS_DIR=$(ls -d ./files/boot/nixos/*-dtbs)/broadcom 208 | chmod u+w $DTBS_DIR 209 | cp ${config.system.build.toplevel}/dtbs/broadcom/bcm2835-rpi-zero-w.dtb $DTBS_DIR/bcm2835-rpi-zero-w.dtb 210 | chmod u-w $DTBS_DIR 211 | ''; 212 | }; 213 | } 214 | -------------------------------------------------------------------------------- /modules/sd-image/rpizero2/sd-image.nix: -------------------------------------------------------------------------------- 1 | # This module extends the official sd-image.nix with the following: 2 | # - ability to add a swap partition to the built image 3 | # - ability to add options to the config.txt firmware 4 | # - fix the uboot bug with pi zero 2 5 | # Related issue: https://github.com/NixOS/nixpkgs/issues/216886 6 | # Original file: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/sd-card/sd-image.nix 7 | { 8 | nixpkgs, 9 | config, 10 | lib, 11 | pkgs, 12 | ... 13 | }: 14 | with lib; let 15 | rootfsImage = pkgs.callPackage "${pkgs.path}/nixos/lib/make-ext4-fs.nix" ({ 16 | inherit (config.sdImage) storePaths; 17 | compressImage = config.sdImage.compressImage; 18 | populateImageCommands = config.sdImage.populateRootCommands; 19 | volumeLabel = "NIXOS_SD"; 20 | } 21 | // optionalAttrs (config.sdImage.rootPartitionUUID != null) { 22 | uuid = config.sdImage.rootPartitionUUID; 23 | }); 24 | in { 25 | options.sdImage = { 26 | swap = { 27 | enable = mkEnableOption "Create a swap partition."; 28 | partitionName = mkOption { 29 | type = types.str; 30 | default = "SWAP"; 31 | description = lib.mdDoc '' 32 | Name of the partition which holds the swap. 33 | ''; 34 | }; 35 | size = mkOption { 36 | type = types.int; 37 | default = 2 * 1024; 38 | description = lib.mdDoc '' 39 | Size of the swap partition, in megabytes. 40 | ''; 41 | }; 42 | }; 43 | 44 | extraFirmwareConfig = mkOption { 45 | type = types.attrs; 46 | default = {}; 47 | description = lib.mdDoc '' 48 | Extra configuration to be added to config.txt. 49 | ''; 50 | }; 51 | }; 52 | 53 | config = { 54 | # Override of the sd image build to optionally add a swap partition 55 | system.build.sdImage = lib.mkForce (pkgs.callPackage 56 | ({ 57 | stdenv, 58 | dosfstools, 59 | e2fsprogs, 60 | mtools, 61 | libfaketime, 62 | util-linux, 63 | zstd, 64 | }: 65 | stdenv.mkDerivation { 66 | name = config.sdImage.imageName; 67 | 68 | nativeBuildInputs = 69 | [dosfstools e2fsprogs libfaketime mtools util-linux] 70 | ++ lib.optional config.sdImage.compressImage zstd; 71 | 72 | inherit (config.sdImage) imageName compressImage; 73 | 74 | buildCommand = '' 75 | mkdir -p $out/nix-support $out/sd-image 76 | export img=$out/sd-image/${config.sdImage.imageName} 77 | 78 | echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system 79 | if test -n "$compressImage"; then 80 | echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products 81 | else 82 | echo "file sd-image $img" >> $out/nix-support/hydra-build-products 83 | fi 84 | 85 | root_fs=${rootfsImage} 86 | ${lib.optionalString config.sdImage.compressImage '' 87 | root_fs=./root-fs.img 88 | echo "Decompressing rootfs image" 89 | zstd -d --no-progress "${rootfsImage}" -o $root_fs 90 | ''} 91 | 92 | # Set swap size. Set it to 0 it swap is disabled. 93 | swapSize=${toString ( 94 | if config.sdImage.swap.enable 95 | then config.sdImage.swap.size 96 | else 0 97 | )} 98 | # The root partition is #2 if there is no swap, but is #3 is there is one 99 | rootPartitionNumber=${toString ( 100 | if config.sdImage.swap.enable 101 | then 3 102 | else 2 103 | )} 104 | 105 | # Gap in front of the first partition, in MiB 106 | gap=${toString config.sdImage.firmwarePartitionOffset} 107 | 108 | # Create the image file sized to fit /boot/firmware and /, plus slack for the gap. 109 | rootSizeBlocks=$(du -B 512 --apparent-size $root_fs | awk '{ print $1 }') 110 | firmwareSizeBlocks=$((${toString config.sdImage.firmwareSize} * 1024 * 1024 / 512)) 111 | # Note: swap size is 0 if swap is disabled 112 | imageSize=$((rootSizeBlocks * 512 + firmwareSizeBlocks * 512 + gap * 1024 * 1024 + swapSize * 1024 * 1024)) 113 | truncate -s $imageSize $img 114 | 115 | # type=b is 'W95 FAT32', type=82 is 'Linux swap / Solaris', type=83 is 'Linux'. 116 | # The "bootable" partition is where u-boot will look file for the bootloader 117 | # information (dtbs, extlinux.conf file). 118 | 119 | sfdisk $img < 0) 185 | ( 186 | let 187 | # Convert the set into a string of lines of "key=value" pairs. 188 | keyValueMap = name: value: name + "=" + toString value; 189 | keyValueList = lib.mapAttrsToList keyValueMap config.sdImage.extraFirmwareConfig; 190 | extraFirmwareConfigString = lib.concatStringsSep "\n" keyValueList; 191 | in 192 | lib.mkAfter 193 | '' 194 | config=firmware/config.txt 195 | # The initial file has just been created without write permissions. Add them to be able to append the file. 196 | chmod u+w $config 197 | echo "\n# Extra configuration" >> $config 198 | echo "${extraFirmwareConfigString}" >> $config 199 | chmod u-w $config 200 | '' 201 | ); 202 | 203 | # Ugly hack to make it work with Pi Zero 2 204 | sdImage.populateRootCommands = lib.mkForce '' 205 | mkdir -p ./files/boot 206 | ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot 207 | DTBS_DIR=$(ls -d ./files/boot/nixos/*-dtbs)/broadcom 208 | chmod u+w $DTBS_DIR 209 | cp ${config.system.build.toplevel}/dtbs/broadcom/bcm2837-rpi-zero-2-w.dtb $DTBS_DIR/bcm2837-rpi-zero-2.dtb 210 | 211 | chmod u-w $DTBS_DIR 212 | ''; 213 | }; 214 | } 215 | --------------------------------------------------------------------------------