Skip to content

Commit 70665f6

Browse files
committed
spacemit/k3-pico-itx: init
1 parent c97bc4d commit 70665f6

10 files changed

Lines changed: 642 additions & 0 deletions

File tree

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@
424424
kobol-helios4 = import ./kobol/helios4;
425425
samsung-np900x3c = import ./samsung/np900x3c;
426426
slimbook-hero-rpl-rtx = import ./slimbook/hero/rpl-rtx;
427+
spacemit-k3-pico-itx = import ./spacemit/k3-pico-itx;
427428
starfive-visionfive-v1 = import ./starfive/visionfive/v1;
428429
starfive-visionfive-2 = import ./starfive/visionfive/v2;
429430
starlabs-starlite-i5 = import ./starlabs/starlite/i5;

spacemit/k3-pico-itx/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# SpacemiT K3 Pico-ITX
2+
3+
NixOS support for the [SpacemiT K3 Pico-ITX](https://www.spacemit.com/community/document/info?nodepath=hardware%2Feco%2Fk3_pico%2Fpico_user_guide.md&lang=en) single-board
4+
computer, built around the SpacemiT K3 SoC (RVA23 RISC-V).
5+
6+
## Hardware
7+
8+
| Component | Detail |
9+
| --------- | ------ |
10+
| SoC | SpacemiT K3 (RVA23, 64-bit RISC-V) |
11+
| CPU | 16 cores: 8× X100 @ 2.4 GHz + 8× A100 @ 2.0 GHz |
12+
| Memory | LPDDR5, up to 32 GB |
13+
| Storage | PCIe Gen3 ×4 (NVMe), internal UFS, microSD |
14+
| Network | RTL8211F 1GbE (`end0`), RTL8127 10GbE (PCIe), RTL8852BE Wi-Fi 6 (PCIe) |
15+
| Firmware | EDK2 UEFI + U-Boot + OpenSBI |
16+
17+
## Usage
18+
19+
Add the module to your configuration:
20+
21+
```nix
22+
{
23+
imports = [
24+
"${nixos-hardware}/spacemit/k3-pico-itx"
25+
];
26+
}
27+
```
28+
29+
This gives you the base setup with the vendor `linux-6.18` kernel and
30+
EDK2/U-Boot/OpenSBI. I plan to move to the mainline kernel.
31+
32+
### Building an SD-image
33+
34+
```nix
35+
{
36+
imports = [
37+
"${nixos-hardware}/spacemit/k3-pico-itx/sd-image.nix"
38+
];
39+
40+
# Set a password or add an SSH key so you can log in
41+
# users.users.nixos.password = "changeme";
42+
# users.users.nixos.openssh.authorizedKeys.keys = [ "ssh-ed25519 ..." ];
43+
}
44+
```
45+
46+
```sh
47+
nix build .#sd-image
48+
```
49+
50+
## Cache
51+
52+
To install and update your system I set up a binary cache:
53+
`build05.ynh.ovh`
54+
This saves you from compiling everything locally.
55+
Here is how to add it to your configuration:
56+
57+
```nix
58+
nix.settings = {
59+
substituters = [ "https://build05.ynh.ovh" ];
60+
trusted-public-keys = [
61+
"build05.ynh.ovh:bLxWKPjbKYOFxqrjOxv+cdwS3kFLuHEf1k6j8fAxbzM="
62+
];
63+
};
64+
```
65+
66+
Here is how to use it without adding it to your configuration:
67+
68+
```sh
69+
nix build \
70+
--substituters https://build05.ynh.ovh \
71+
--trusted-public-keys "build05.ynh.ovh:bLxWKPjbKYOFxqrjOxv+cdwS3kFLuHEf1k6j8fAxbzM="
72+
```
73+
74+
PS: This is a cache maintained on a voluntary basis for the K3 and riscv64
75+
hardware. I can't guarantee its availability, nor that everything is already
76+
built on it. The Hydra infrastructure is still being deployed, so please be
77+
lenient in that regard.
78+
79+
## HMP configuration
80+
81+
The X100 and A100 clusters have different vector widths (`VLENB=32` vs `VLENB=128`).
82+
83+
You can configure HMP at runtime:
84+
85+
`echo strict > /sys/kernel/spacemit_hmp/mode` (default)
86+
87+
or
88+
89+
`echo permissive > /sys/kernel/spacemit_hmp/mode`
90+
91+
Permissive mode lets you use the 8 A100 cores in addition to the X100 cores.
92+
However, I deliberately apply a segmentation between the two clusters because of a
93+
VLEN issue.
94+
95+
If you force tasks across both clusters anyway (e.g. via `taskset`), it will cause
96+
crypto corruption.
97+
98+
I also made a small module for this:
99+
100+
```nix
101+
hardware.spacemit.hmp = {
102+
enable = true;
103+
mode = "permissive"; # or "strict"
104+
};
105+
```
106+
107+
- **`strict`** (default): uses the X100 cores only.
108+
- **`permissive`**: uses both the X100 and A100 cores, but with a segmentation
109+
between the clusters.
110+
111+
An alternative is still available to use all 16 cores without segmentation, with
112+
this:
113+
114+
```nix
115+
environment.variables.OPENSSL_riscvcap = "RV64GC";
116+
```
117+
118+
## UEFI
119+
120+
To get UEFI I made a small script, to be run from Bianbu:
121+
122+
https://github.com/liberodark/k3-uefi-flash
123+
124+
## Status
125+
126+
Working:
127+
128+
- Boot to NixOS, SSH reachable
129+
- NVMe root (PCIe Gen3 ×4), 1GbE (`end0`)
130+
- All 16 cores usable (see HMP notes above)
131+
132+
Known issues:
133+
134+
- I noticed a reboot issue, so I force it with `reboot -ff`.
135+
136+
## Upstream status
137+
138+
- [Kernel](https://github.com/spacemit-com/linux/wiki)
139+
- [OpenSBI](https://github.com/spacemit-com/opensbi-upstream/wiki)
140+
- [U-Boot](https://github.com/spacemit-com/u-boot/wiki)
141+
- [LLVM/GCC](https://github.com/spacemit-com/.github/blob/main/upstream-status/toolchain.md)
142+
- [llama.cpp](https://github.com/spacemit-com/llama.cpp/wiki)

spacemit/k3-pico-itx/default.nix

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
{
2+
config,
3+
lib,
4+
pkgs,
5+
...
6+
}:
7+
8+
{
9+
imports = [ ./firmware.nix ];
10+
11+
boot = {
12+
consoleLogLevel = lib.mkDefault 7;
13+
14+
kernelPackages = lib.mkDefault (
15+
pkgs.linuxPackagesFor (
16+
pkgs.callPackage ./linux.nix {
17+
inherit (config.boot) kernelPatches;
18+
}
19+
)
20+
);
21+
22+
kernelParams = [
23+
"earlycon=sbi"
24+
"keep_bootcon"
25+
"systemd.journald.forward_to_console=1"
26+
"systemd.log_target=kmsg"
27+
"systemd.log_level=info"
28+
"clk_ignore_unused"
29+
"pd_ignore_unused"
30+
"root=PARTLABEL=nixos-rootfs"
31+
"rootwait"
32+
"rootfstype=ext4"
33+
];
34+
35+
initrd = {
36+
availableKernelModules = [
37+
"usb_storage"
38+
"uas"
39+
"nvme"
40+
"nvme_core"
41+
];
42+
kernelModules = [
43+
"erofs"
44+
"loop"
45+
];
46+
};
47+
48+
loader = {
49+
systemd-boot.enable = lib.mkDefault true;
50+
systemd-boot.consoleMode = lib.mkDefault "auto";
51+
timeout = lib.mkDefault 3;
52+
efi.canTouchEfiVariables = lib.mkDefault false;
53+
efi.efiSysMountPoint = lib.mkDefault "/boot";
54+
generic-extlinux-compatible.enable = lib.mkDefault false;
55+
};
56+
57+
zfs.forceImportRoot = lib.mkDefault false;
58+
};
59+
60+
hardware.deviceTree = {
61+
enable = lib.mkDefault true;
62+
name = lib.mkDefault "spacemit/k3-pico-itx.dtb";
63+
};
64+
65+
boot.initrd.systemd.enable = lib.mkDefault true;
66+
system.nixos-init.enable = lib.mkDefault true;
67+
system.etc.overlay.enable = lib.mkDefault true;
68+
services.userborn.enable = lib.mkDefault true;
69+
70+
systemd.services."serial-getty@ttyS0" = {
71+
enable = true;
72+
wantedBy = [ "getty.target" ];
73+
serviceConfig.Restart = "always";
74+
};
75+
}

spacemit/k3-pico-itx/edk2.nix

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
stdenvNoCC,
3+
fetchFromGitHub,
4+
}:
5+
6+
stdenvNoCC.mkDerivation {
7+
pname = "edk2-spacemit-k3";
8+
version = "ubuntu26.04-20260509";
9+
10+
src = fetchFromGitHub {
11+
owner = "spacemit-com";
12+
repo = "K3-Ubuntu-Images";
13+
tag = "ubuntu26.04-20260509";
14+
hash = "sha256-J0T3T/gOhKmld1du7J2z+DimZXShb+zoON3DHIz4Hy0=";
15+
};
16+
17+
dontConfigure = true;
18+
dontBuild = true;
19+
20+
installPhase = ''
21+
runHook preInstall
22+
23+
mkdir -p $out
24+
cp gadget.in/edk2.itb $out/
25+
26+
runHook postInstall
27+
'';
28+
}

spacemit/k3-pico-itx/firmware.nix

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
{
2+
config,
3+
pkgs,
4+
lib,
5+
...
6+
}:
7+
8+
let
9+
cfg = config.hardware.k3-pico-itx;
10+
in
11+
12+
{
13+
options.hardware.k3-pico-itx = {
14+
opensbi = {
15+
src = lib.mkOption {
16+
description = "K3 Pico-ITX OpenSBI source override.";
17+
type = lib.types.nullOr lib.types.package;
18+
default = null;
19+
};
20+
patches = lib.mkOption {
21+
description = "Additional patches to apply to K3 Pico-ITX OpenSBI.";
22+
type = lib.types.nullOr (lib.types.listOf lib.types.package);
23+
default = null;
24+
};
25+
};
26+
27+
uboot = {
28+
src = lib.mkOption {
29+
description = "K3 Pico-ITX U-Boot source override.";
30+
type = lib.types.nullOr lib.types.package;
31+
default = null;
32+
};
33+
patches = lib.mkOption {
34+
description = "Additional patches to apply to K3 Pico-ITX U-Boot.";
35+
type = lib.types.nullOr (lib.types.listOf lib.types.package);
36+
default = null;
37+
};
38+
};
39+
40+
fsbl = {
41+
src = lib.mkOption {
42+
description = "K3 Pico-ITX FSBL source override.";
43+
type = lib.types.nullOr lib.types.package;
44+
default = null;
45+
};
46+
patches = lib.mkOption {
47+
description = "Additional patches to apply to K3 Pico-ITX FSBL.";
48+
type = lib.types.nullOr (lib.types.listOf lib.types.package);
49+
default = null;
50+
};
51+
};
52+
53+
edk2 = {
54+
src = lib.mkOption {
55+
description = "K3 Pico-ITX EDK2 (UEFI) source override.";
56+
type = lib.types.nullOr lib.types.package;
57+
default = null;
58+
};
59+
};
60+
};
61+
62+
config = {
63+
system.build = {
64+
opensbi = (pkgs.callPackage ./opensbi.nix { }).overrideAttrs (
65+
_final: prev: {
66+
src = if cfg.opensbi.src != null then cfg.opensbi.src else prev.src;
67+
patches = if cfg.opensbi.patches != null then cfg.opensbi.patches else (prev.patches or [ ]);
68+
}
69+
);
70+
71+
uboot = (pkgs.callPackage ./uboot.nix { }).overrideAttrs (
72+
_final: prev: {
73+
src = if cfg.uboot.src != null then cfg.uboot.src else prev.src;
74+
patches = if cfg.uboot.patches != null then cfg.uboot.patches else (prev.patches or [ ]);
75+
}
76+
);
77+
78+
fsbl = (pkgs.callPackage ./fsbl.nix { }).overrideAttrs (
79+
_final: prev: {
80+
src = if cfg.fsbl.src != null then cfg.fsbl.src else prev.src;
81+
patches = if cfg.fsbl.patches != null then cfg.fsbl.patches else (prev.patches or [ ]);
82+
}
83+
);
84+
85+
edk2 = (pkgs.callPackage ./edk2.nix { }).overrideAttrs (
86+
_final: prev: {
87+
src = if cfg.edk2.src != null then cfg.edk2.src else prev.src;
88+
}
89+
);
90+
91+
updater-sd = pkgs.writeShellApplication {
92+
name = "k3-pico-itx-firmware-update-sd";
93+
runtimeInputs = [ pkgs.coreutils ];
94+
text = ''
95+
dev=''${1:-/dev/mmcblk0}
96+
dd if=${config.system.build.fsbl}/FSBL.bin of=''${dev}p3 conv=fsync,notrunc
97+
dd if=${config.system.build.opensbi}/share/opensbi/lp64/generic/firmware/fw_dynamic.itb of=''${dev}p5 conv=fsync,notrunc
98+
dd if=${config.system.build.edk2}/edk2.itb of=''${dev}p6 conv=fsync,notrunc
99+
'';
100+
};
101+
};
102+
};
103+
}

spacemit/k3-pico-itx/fsbl.nix

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
buildUBoot,
3+
fetchFromGitHub,
4+
}:
5+
6+
buildUBoot {
7+
version = "2022.10-k3-br-v1.0.y";
8+
9+
src = fetchFromGitHub {
10+
owner = "liberodark";
11+
repo = "spacemit-uboot-2022.10";
12+
rev = "368953aa0b648528ddafa5b6baa73507448ab94d";
13+
hash = "sha256-LTtxHzL5aoMLlv8DsgEoyIM0JrwYYzNlHCAmXzixScI=";
14+
};
15+
16+
defconfig = "k3_defconfig";
17+
18+
filesToInstall = [
19+
"FSBL.bin"
20+
"bootinfo_block.bin"
21+
"bootinfo_spinor.bin"
22+
"bootinfo_spinand.bin"
23+
];
24+
}

0 commit comments

Comments
 (0)