diff --git a/README.md b/README.md index b71337bbf..cc234bdce 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,7 @@ See code for all available configurations. | [Purism Librem 13v3](purism/librem/13v3) | `` | | [Purism Librem 15v3](purism/librem/13v3) | `` | | [Purism Librem 5r4](purism/librem/5r4) | `` | +| [Radxa ROCK 4C+](radxa/rock-4c-plus) | `` | | [Raspberry Pi 2](raspberry-pi/2) | `` | | [Raspberry Pi 3](raspberry-pi/3) | `` | | [Raspberry Pi 4](raspberry-pi/4) | `` | diff --git a/flake.nix b/flake.nix index c30a38536..2cc531cb4 100644 --- a/flake.nix +++ b/flake.nix @@ -291,6 +291,7 @@ raspberry-pi-3 = import ./raspberry-pi/3; raspberry-pi-4 = import ./raspberry-pi/4; raspberry-pi-5 = import ./raspberry-pi/5; + rock-4c-plus = import ./radxa/rock-4c-plus; kobol-helios4 = import ./kobol/helios4; samsung-np900x3c = import ./samsung/np900x3c; slimbook-hero-rpl-rtx = import ./slimbook/hero/rpl-rtx; diff --git a/radxa/README.md b/radxa/README.md new file mode 100644 index 000000000..b17e6b677 --- /dev/null +++ b/radxa/README.md @@ -0,0 +1,94 @@ +# NixOS support for Radxa devices + +Radxa provides the NixOS implementation in the form of `nixos-hardware` modules +for advanced users. + +Our goals are: + +* Only use `nixpkgs` provided packages. +* Provide a consistent and simple experience to use our NixOS module. +* Targetted audiences are advanced users who care mostly about CPU compute, storage, and network. +* No support guarantee. We are not here to teach people how to use NixOS. + +We explicitly want to avoid packaging the entire vendor SDK bootloader and kernel +in Nix. Those are not going to be accepted in `nixpkgs`, and our targetted audiences +like homelabbers generally ignore the additional hardware features. + +This also aligns with [NixOS on ARM](https://wiki.nixos.org/wiki/NixOS_on_ARM)'s +definition of "support": + +> Support for those board assumes as much is supported as Mainline Linux supports. + +## Characteristic of the default profiles + +* Using `linuxPackages_latest` +* `bcachefs` rootfs with zstd compression and password-less encryption enabled +* EFI boot chain provided by `systemd-boot` +* Default serial console enabled with baud rate matches the platform firmware +* No automatic partition expansion, as the module is only focusing on hardware + +## Common Nix flake pattern + +Below is an annoated flake example to create the initial boot image. + +``` +{ + description = "Example NixOS configurations for Radxa product"; + # To build, run `nix build .#nixosConfigurations.radxa.config.system.build.diskoImages` + + inputs = { + disko.url = "github:nix-community/disko"; + disko.inputs.nixpkgs.follows = "nixpkgs"; + nixos-hardware.url = "github:NixOS/nixos-hardware"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + nixpkgs-unfree.url = "github:numtide/nixpkgs-unfree/nixos-unstable"; + }; + + outputs = inputs@{ + self, + disko, + nixos-hardware, + nixpkgs, + nixpkgs-unfree, + }: { + nixosConfigurations = { + radxa = nixpkgs.lib.nixosSystem { + specialArgs = { inherit inputs; }; + system = "aarch64-linux"; + modules = [ + nixos-hardware.nixosModules.rock-4c-plus # Update the system according to your device. + disko.nixosModules.disko # disko usage is optional in the running system, but we need it to generate the initial boot image. + "${nixos-hardware}/radxa/disko.nix" # Common Radxa Disko profile. it is system-agnostic. + { + disko = { + imageBuilder = { + # Avoid double emulation to significantly speed up image building process. + # Update the system according to your host system. + # See https://github.com/nix-community/disko/issues/856 + qemu = nixpkgs.legacyPackages.x86_64-linux.qemu + "/bin/qemu-system-aarch64 -M virt -cpu cortex-a57"; + }; + # Default image size is 2G for a small basic CLI system. + # devices.disk.main.imageSize = "2G"; + }; + + # Override the default bootloader with a cross built one. + # Use this if you do not have binfmt configured on your system. + # For NixOS, please add `boot.binfmt.emulatedSystems = [ "aarch64-linux" ];` to your system configuration. + # Update the system and the firmware package according to your device. + # hardware.radxa.rock-4c-plus.platformFirmware = nixpkgs-unfree.legacyPackages.x86_64-linux.pkgsCross.aarch64-multiplatform.ubootRock4CPlus; + + users.users.radxa = { + isNormalUser = true; + initialPassword = "radxa"; + extraGroups = [ "wheel" ]; + }; + services.openssh.enable = true; + networking.hostName = "radxa"; + system.stateVersion = "24.11"; + } + ]; + }; + }; + }; +} +``` diff --git a/radxa/default.nix b/radxa/default.nix new file mode 100644 index 000000000..fb311df76 --- /dev/null +++ b/radxa/default.nix @@ -0,0 +1,23 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.radxa; +in { + options.hardware.radxa = { + enable = lib.mkEnableOption "Radxa system support"; + }; + + config = lib.mkIf cfg.enable { + boot = { + # Currently enable bcachefs automatically set + # kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + # TODO: Consider removing this line once, we get an LTS kernel that is newer than 6.12 + kernelPackages = lib.mkOverride 990 pkgs.linuxPackages_latest; + supportedFilesystems = [ "bcachefs" ]; + loader.systemd-boot.enable = lib.mkDefault true; + }; + }; +} diff --git a/radxa/disko.nix b/radxa/disko.nix new file mode 100644 index 000000000..30c30a979 --- /dev/null +++ b/radxa/disko.nix @@ -0,0 +1,12 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.radxa; +in { + imports = [ + ../rockchip/disko.nix + ]; +} diff --git a/radxa/rock-4c-plus/default.nix b/radxa/rock-4c-plus/default.nix new file mode 100644 index 000000000..5fb9d5d36 --- /dev/null +++ b/radxa/rock-4c-plus/default.nix @@ -0,0 +1,31 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.radxa.rock-4c-plus; + rkCfg = config.hardware.rockchip; +in { + imports = [ + ../. + ../../rockchip/rk3399 + ]; + + options.hardware.radxa.rock-4c-plus = { + platformFirmware = lib.mkPackageOption pkgs "ubootRock4CPlus" { }; + }; + + config = { + hardware = { + radxa.enable = true; + rockchip = { + rk3399.enable = true; + diskoExtraPostVM = '' + dd conv=notrunc,fsync if=${cfg.platformFirmware}/idbloader.img of=$out/${rkCfg.diskoImageName} bs=512 seek=64 + dd conv=notrunc,fsync if=${cfg.platformFirmware}/u-boot.itb of=$out/${rkCfg.diskoImageName} bs=512 seek=16384 + ''; + }; + }; + }; +} diff --git a/rockchip/default.nix b/rockchip/default.nix new file mode 100644 index 000000000..461baedd7 --- /dev/null +++ b/rockchip/default.nix @@ -0,0 +1,33 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.rockchip; +in { + options.hardware.rockchip = { + enable = lib.mkEnableOption "Rockchip SoC support"; + diskoImageName = lib.mkOption { + type = lib.types.str; + default = "main.raw"; + description = '' + The output image name for Disko. + Can be used by diskoExtraPostVM. + ''; + }; + diskoExtraPostVM = lib.mkOption { + type = lib.types.str; + description = '' + The post VM hook for Disko's Image Builder. + Can be used to install platform firmware like U-Boot. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + boot = { + kernelParams = [ "console=ttyS2,1500000n8" ]; + }; + }; +} diff --git a/rockchip/disko.nix b/rockchip/disko.nix new file mode 100644 index 000000000..7d6b4c9ab --- /dev/null +++ b/rockchip/disko.nix @@ -0,0 +1,62 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.rockchip; +in { + imports = [ + rk3399/disko.nix + ]; + + config = lib.mkIf cfg.enable { + disko = { + imageBuilder = { + extraRootModules = [ "bcachefs" ]; + extraPostVM = cfg.diskoExtraPostVM; + }; + memSize = lib.mkDefault 4096; # Default 1024 MB will throw "Cannot allocate memory" error + devices.disk.main = { + type = "disk"; + imageSize = lib.mkDefault "2G"; + content = { + type = "gpt"; + partitions = { + ESP = { + type = "EF00"; + # Firmware backoff + start = "16M"; + size = "500M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0022" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "bcachefs"; + mountpoint = "/"; + extraArgs = [ + "--metadata_checksum=xxhash" + "--data_checksum=xxhash" + "--compression=zstd" + "--background_compression=zstd" + "--str_hash=siphash" + "--wide_macs" + "--encrypted" + "--no_passphrase" + "--discard" + ]; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/rockchip/rk3399/default.nix b/rockchip/rk3399/default.nix new file mode 100644 index 000000000..3aea18fd7 --- /dev/null +++ b/rockchip/rk3399/default.nix @@ -0,0 +1,20 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.rockchip.rk3399; +in { + imports = [ + ../. + ]; + + options.hardware.rockchip.rk3399 = { + enable = lib.mkEnableOption "Rockchip RK3399 support"; + }; + + config = lib.mkIf cfg.enable { + hardware.rockchip.enable = true; + }; +} diff --git a/rockchip/rk3399/disko.nix b/rockchip/rk3399/disko.nix new file mode 100644 index 000000000..bae10ef55 --- /dev/null +++ b/rockchip/rk3399/disko.nix @@ -0,0 +1,14 @@ +{ lib +, pkgs +, config +, ... +}: +let + cfg = config.hardware.rockchip.rk3399; +in { + config = lib.mkIf cfg.enable { + nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ + "arm-trusted-firmware-rk3399" + ]; + }; +}