Notes on getting NixOS on the Radxa Dragon Q6A
The Radxa Dragon Q6A is a quite capable SBC specially for the price I've paid for it.
As of the time of this writing the latest-nixos-minimal-aarch64-linux.iso fails to boot from USB and loading from the SD-CARD results in a very slow environment. In this setup I'll be installing NixOS on the NVME drive and haven't tested UFS2. Also please take into consideration Radxa is actively working and submiting patches for the platform so by the time you are reading these instructions might be outdated.
Installation steps
So first we need to download the latest version of Radxa OS and use it to update the firmware to at least version 260120.
If you don't have or don't want to connect a display and keyboard UART works fine including the EFI BIOS menu. Make sure to check the Radxa documentation on which pins to connect. If you are using the compatible PoE HAT adapter be mindful it doesn't have passthrough GPIO pins.
You also need to make sure virtualization is disabled on the UEFI firmware otherwise /dev/mtd0 won't be available to flash the SPI. You can enable it later for KVM support.
On Radxa OS (username: radxa, password: radxa) make sure to disable automatic suspend on preferences as it doesn't take into account SSH sessions when suspending the system and some tasks like compiling a kernel might take a long time.
Start by running sudo rsetup and navigating to System → Bootloader Management → Update SPI Bootloader. Select radxa-dragon-q6a and run the scary steps. If rsetup complains about unsupported or missing device and there is no /dev/mtd0 device then you are running with virtualization enabled so you need to go back to the UEFI settings and disable it.
During the process I've observed "error 13 (permission denied)" while trying to erase MTD before it starts to slowly erase and write to the device but those errors don't seem to have influenced the results and the message "The SPI bootloader has been updated successfully" should confirm the update happened.
Reboot and enter the firmware setup to verify you are running 260120. You can also enable virtualization now if you want to.
Back to Radxa OS install Nix using the instructions on https://nixos.org/download/#nix-install-linux for generic Linux:
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon
From now on you will follow the instructions described in https://nixos.org/manual/nixos/stable/#sec-installing-from-other-distro to run a NixOS installation environment on top of Radxa OS. Target system should be UEFI. The important parts are config.boot and config.hardware but you must also disable TPM:
boot = {
kernelPackages = lib.mkDefault (
pkgs.linuxPackagesFor (import ./modules/kernels/dragon.nix { inherit lib pkgs; })
);
kernelParams = [
"console=ttyMSM0,115200n8"
"earlycon"
"keep_bootcon"
];
loader = {
systemd-boot = {
enable = true;
installDeviceTree = true;
};
efi = {
canTouchEfiVariables = false;
};
};
initrd = {
kernelModules = [
"usb_storage"
"nvme"
"xhci_hcd"
];
systemd = {
tpm2 = {
enable = false;
};
};
};
};
systemd = {
tpm2 = {
enable = false;
};
};
MESA has some open source support for Adreno GPU so you can include hardware.graphics without any special configurations.
hardware = {
graphics = {
enable = true;
};
firmware = with pkgs; [
linux-firmware
];
deviceTree = {
enable = true;
name = "qcom/qcs6490-radxa-dragon-q6a.dtb";
};
};
Custom kernel module (./modules/kernels/dragon.nix)
Extracted from Cryolitia-Forks/nixos-hardware/tree/q6a
{
lib,
pkgs,
...
}:
pkgs.buildLinux {
defconfig = "qcom_module_defconfig";
version = "6.18.2-1-q6a-radxa";
modDirVersion = "6.18.2";
src = pkgs.fetchFromGitHub {
owner = "radxa";
repo = "kernel";
# Use the same kernel commit ID as
# https://github.com/radxa-pkg/linux-qcom/tree/6.18.2-1
rev = "ca7680ac08f031ed0a952dbc6174ced3d513bef9";
hash = "sha256-xCgW/2iaWu9JWz3LLeV/xwzvtx5JComcPZpgH7rnOgw=";
};
structuredExtraConfig = with lib.kernel; {
EFI_ZBOOT = lib.mkForce no;
NVME_AUTH = lib.mkForce yes;
};
extraConfig = ''
COMPRESSED_INSTALL n
DRM_NOVA n
NOVA_CORE n
WLAN_VENDOR_AIC8800 n
'';
ignoreConfigErrors = true;
}
Compiling the kernel on the device might take a long time. You might consider using an external builder specially if you have a powerful ARM64 machine such as Apple Silicon.
ln -sf /nix/var/nix/profiles/system/sw/bin /mnt/sbin to satisfy the installer. You can remove it later.
What doesn't work?
- Secure Boot: no support for it.
- TPM: no support for it.
- PoE HAT fan which might be a blessing in disguise considering how noisy it was when I enabled it in Radxa OS.
- The Hexagon NPU seems to be detected but the SDK provided by Qualcomm is not very friendly. They provide a build environment x86_64 OCI image so they assume people won't be using their products?
Some useful outputs
Power draw
Taken from the PoE switch metrics. The graph includes both idle and a few hours under load compiling the Linux kernel.
/proc/cpuinfo
processor : 0
processor : 0
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x2
CPU part : 0xd05
CPU revision : 0
processor : 1
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x2
CPU part : 0xd05
CPU revision : 0
processor : 2
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x2
CPU part : 0xd05
CPU revision : 0
processor : 3
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x2
CPU part : 0xd05
CPU revision : 0
processor : 4
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd41
CPU revision : 1
processor : 5
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd41
CPU revision : 1
processor : 6
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd41
CPU revision : 1
processor : 7
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd41
CPU revision : 1
ethtool
Settings for enp1s0:
Supported ports: [ TP MII ]
Supported link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Supported FEC modes: Not reported
Advertised link modes: 10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised pause frame use: Symmetric Receive-only
Advertised auto-negotiation: Yes
Advertised FEC modes: Not reported
Link partner advertised link modes: 100baseT/Half 100baseT/Full
1000baseT/Full
Link partner advertised pause frame use: Symmetric
Link partner advertised auto-negotiation: Yes
Link partner advertised FEC modes: Not reported
Speed: 1000Mb/s
Duplex: Full
Auto-negotiation: on
master-slave cfg: preferred slave
master-slave status: master
Port: Twisted Pair
PHYAD: 0
Transceiver: external
MDI-X: Unknown
Supports Wake-on: pumbg
Wake-on: d
Link detected: yes
lspci
# The last device is my aftermarket NVMe.
0000:00:00.0 PCI bridge: Qualcomm Technologies, Inc SM8250 PCIe Root Complex [Snapdragon 865/870 5G]
0000:01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller (rev 1b)
0001:00:00.0 PCI bridge: Qualcomm Technologies, Inc SM8250 PCIe Root Complex [Snapdragon 865/870 5G]
0001:01:00.0 Non-Volatile memory controller: SK hynix Gold P31/BC711/PC711 NVMe Solid State Drive
dmesg
dragonq6a_dmesg.txtcryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1 2766691 iterations per second for 256-bit key
PBKDF2-sha256 5363560 iterations per second for 256-bit key
PBKDF2-sha512 1696724 iterations per second for 256-bit key
PBKDF2-ripemd160 985503 iterations per second for 256-bit key
PBKDF2-whirlpool 496484 iterations per second for 256-bit key
argon2i 4 iterations, 910471 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
argon2id 4 iterations, 899956 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
# Algorithm | Key | Encryption | Decryption
aes-cbc 128b 1211.6 MiB/s 2550.4 MiB/s
serpent-cbc 128b 89.8 MiB/s 100.3 MiB/s
twofish-cbc 128b 141.8 MiB/s 145.3 MiB/s
aes-cbc 256b 972.3 MiB/s 2287.4 MiB/s
serpent-cbc 256b 89.8 MiB/s 100.4 MiB/s
twofish-cbc 256b 142.0 MiB/s 145.4 MiB/s
aes-xts 256b 1907.0 MiB/s 1884.3 MiB/s
serpent-xts 256b 92.7 MiB/s 102.4 MiB/s
twofish-xts 256b 152.5 MiB/s 149.9 MiB/s
aes-xts 512b 1710.4 MiB/s 1696.0 MiB/s
serpent-xts 512b 92.8 MiB/s 102.7 MiB/s
twofish-xts 512b 152.8 MiB/s 150.5 MiB/s
Notes on NPU
The FastRPC devices that are used to communicate with the NPU are detected:
crw------- 10,264 root 26 Apr 19:40 /dev/fastrpc-adsp
crw------- 10,263 root 26 Apr 19:40 /dev/fastrpc-cdsp
crw------- 10,262 root 26 Apr 19:40 /dev/fastrpc-cdsp-securei
However my attempts at building llama-cpp for Hexagon core dumps after attempting to establish a connection to the device (full error log included in original notes).
ggml-hex: Loading driver libcdsprpc.so
ggml-hex: FastRPC capability query failed (err -1)
ggml-hex: failed to query HTP version (err -1) defaulting to v73
ggml-hex: Hexagon backend (experimental) : allocating new registry : ndev 1
ggml-hex: Hexagon Arch version v73
ggml-hex: failed to get URI for session 0 : error 0xffffffff. Falling back to single session URI: file:///libggml-htp-v73.so?htp_iface_skel_handle_invoke&_modver=1.0&_dom=cdsp
ggml-hex: failed to enable unsigned PD for session 0 : error 0xffffffff
ggml-hex: releasing session: HTP0
ggml-hex: failed to create device/session 0
/build/ggml/src/ggml-backend.cpp:584: GGML_ASSERT(device) failed
/opt/llama.cpp/lib/libggml-base.so.0(+0xfa90)[0xffffab31fa90]
/opt/llama.cpp/lib/libggml-base.so.0(ggml_print_backtrace+0x244)[0xffffab31fa6c]
/opt/llama.cpp/lib/libggml-base.so.0(ggml_abort+0xe0)[0xffffab31eca0]
/opt/llama.cpp/lib/libggml-base.so.0(ggml_backend_dev_get_props+0x0)[0xffffab33ae58]
/opt/llama.cpp/lib/libllama-common.so.0(+0xc982c)[0xffffab9c982c]
/opt/llama.cpp/lib/libllama-common.so.0(+0x102b14)[0xffffaba02b14]
/opt/llama.cpp/lib/libllama-common.so.0(+0xfaf60)[0xffffab9faf60]
/opt/llama.cpp/lib/libllama-common.so.0(_Z19common_params_parseiPPcR13common_params13llama_examplePFviS0_E+0x1840)[0xffffab9f9cc4]
llama-server(+0x1dd10)[0xaaaacdcddd10]
/lib/aarch64-linux-gnu/libc.so.6(+0x284c4)[0xffffaadf84c4]
/lib/aarch64-linux-gnu/libc.so.6(__libc_start_main+0x98)[0xffffaadf8598]
llama-server(+0x1b870)[0xaaaacdcdb870]
Aborted (core dumped)