about summary refs log tree commit diff stats
path: root/content/post/nixos-on-nanopi-r5s.md
blob: 7e466ae1339e90093cbeb7142cf7dca8911e9ccc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
+++
title = "Running NixOS on a NanoPi R5S"
date = 2023-07-30T08:51:46Z
[taxonomies]
tags = ["NixOS", "home-networking", "infrastructure"]
+++

I managed to get [NixOS](https://nixos.org) running on my [NanoPi R5S](https://www.friendlyelec.com/index.php?route=product/product&product_id=287) ([FriendlyElec Wiki](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R5S)).

Firstly, I flashed a pre-built stock Debian image from [inindev](https://github.com/inindev/nanopi-r5) to an SD card. This can be used as a rescue system later on. 

From that SD card, I then flashed the same system onto the internal <abbr title="embedded MultiMediaCard">eMMC</abbr> Storage. I only really needed to this to ensure UBoot was correctly installed; I think there will be an easier way to do it.

I had nix already installed on the <abbr title="Non-Volatile Memory Express">NVMe</abbr> <abbr title="Solid-State Drive">SSD</abbr> along with a home directory. I bind-mounted `/nix` and `/home` following the fstab I had previously set up:

```conf
UUID=replaceme  /mnt    ext4    relatime,lazytime   0 2
/mnt/nix        /nix    none    defaults,bind       0 0
/mnt/srv        /srv    none    defaults,bind       0 0
/mnt/home       /home   none    defaults,bind       0 0
```

I then created a user for myself using that home directory, I had full access to nix in the new Debian environment. This meant I had access to `nixos-install`. 

I wanted to use the [extlinux support in UBoot](https://u-boot.readthedocs.io/en/latest/develop/distro.html#boot-configuration-files), so I made `/mnt/boot` point to `/boot` on the <abbr>eMMC</abbr>:

```sh
mkdir /mnt/{emmc,boot}
mount LABEL=rootfs /mnt/emmc
mount --bind /mnt/emmc /mnt/boot
```

<aside>
One could <em>probably</em> delete everything else on the <abbr>eMMC</abbr> and move the contents of <code>/mnt/emmc/boot</code> to <code>/mnt/emmc</code>, thus obviating the need to bind-mount <code>/boot</code>
</aside>

I ran `nixos-generate-config` as usual, which set up the mount points in `hardware-configuration.nix` correctly. `configuration.nix` needed a bit of tweaking. My first booting configuration was something like this, mostly borrowed from [Artem Boldariev's comment](https://github.com/inindev/nanopi-r5/issues/11#issue-1789308883):

```nix
{ config
, pkgs
, lib
, ...
}:
let
  fsTypes = [ "f2fs" "ext" "exfat" "vfat" ];
in
{
  imports = [ ./hardware-configuration.nix ];
  boot = {
    kernelParams = [ "console=tty0" ];
    # partial Rockchip related changes from Debian 12 kernel version 6.1
    # Also, see here:
    # https://discourse.nixos.org/t/how-to-provide-missing-headers-to-a-kernel-build/11422/3
    kernelPatches = [
      {
        name = "rockchip-config.patch";
        patch = null;
        extraConfig = ''
          PHY_ROCKCHIP_PCIE Y
          PCIE_ROCKCHIP_EP y
          PCIE_ROCKCHIP_DW_HOST y
          ROCKCHIP_VOP2 y
        '';
      }
      {
        name = "status-leds.patch";
        patch = null;
        # old:
        # LEDS_TRIGGER_NETDEV y
        extraConfig = ''
          LED_TRIGGER_PHY y
          USB_LED_TRIG y
          LEDS_BRIGHTNESS_HW_CHANGED y
          LEDS_TRIGGER_MTD y
        '';
      }
    ];
    
    supportedFilesystems = fsTypes;
    initrd.supportedFilesystems = fsTypes;

    initrd.availableKernelModules = [
      ## Rockchip
      ## Storage
      "sdhci_of_dwcmshc"
      "dw_mmc_rockchip"

      "analogix_dp"
      "io-domain"
      "rockchip_saradc"
      "rockchip_thermal"
      "rockchipdrm"
      "rockchip-rga"
      "pcie_rockchip_host"
      "phy-rockchip-pcie"
      "phy_rockchip_snps_pcie3"
      "phy_rockchip_naneng_combphy"
      "phy_rockchip_inno_usb2"
      "dwmac_rk"
      "dw_wdt"
      "dw_hdmi"
      "dw_hdmi_cec"
      "dw_hdmi_i2s_audio"
      "dw_mipi_dsi"
    ];
    loader = {
      timeout = 3;
      grub.enable = false;
      generic-extlinux-compatible = {
        enable = true;
        useGenerationDeviceTree = true;
      };
    };
  };
  # Most Rockchip CPUs (especially with hybrid cores) work best with "schedutil"
  powerManagement.cpuFreqGovernor = "schedutil";
  
  boot.kernelParams = [
    "console=tty1"
    "console=ttyS2,1500000"
    "earlycon=uart8250,mmio32,0xfe660000"
  ];
  # Let's blacklist the Rockchips RTC module so that the
  # battery-powered HYM8563 (rtc_hym8563 kernel module) will be used
  # by default
  boot.blacklistedKernelModules = [ "rtc_rk808" ];

  # ... typical config omitted for brevity
}
```

Due to the custom kernel configuration, building takes a while. I set up a [distributed build](https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html) to speed things up, using a [Hetzner Cloud](https://www.hetzner.com/cloud) CAX21 ARM64 instance (although I could have used an x86_64 system with one of the methods mentioned on the [NixOS on ARM NixOS wiki page](https://nixos.wiki/wiki/NixOS_on_ARM#Build_your_own_image_natively)). This made for a very long `nixos-install` command line:

```sh
sudo env PATH=$PATH =nixos-install --root /mnt --no-channel-copy --channel https://nixos.org/channels/nixos-23.05 --option builders'ssh://my-host aarch64-linux /root/.ssh/id_pappel_nixpkgs 4 2 big-parallel' --option builders-use-substitutes true --max-jobs 0
```

I added `setenv bootmeths "extlinux"` to `/boot/boot.txt` and ran `/boot/mkscr.sh` as root to ensure that UBoot would search for the `extlinux.conf` file