Repository: NixOS/nixos-hardware
Pull request #1444: lenovo-thinkpad-x13s: Add support for aarch64 system
Author: login: phodina
Created: 2025-04-13T08:17:50Z | Merged: 2025-04-24T14:00:55Z

###### Description of changes
Add support for the Lenovo X13s machine running on aarch64 architecture of the Snapdragon Elite X gen 3.

There are few issues:
- custom kernel (not sure where to upstream), should it be here or go directly to the nixpkgs
(the kernel could be reused for similar machines running on the aarch64 snapdragon and using UEFI)
- caching of the kernel as the build takes long time
- creation of install iso https://github.com/kuruczgy/x1e-nixos-config/pull/108
- support for DTB in the install ISO https://github.com/NixOS/nixpkgs/pull/396334
- hardcoded Wifi/BT MAC addresses
- BIOS/UEFI firmware update, have option to either [create update image](https://support.lenovo.com/us/en/downloads/ds556845-bios-update-utility-bootable-cd-for-windows-11-thinkpad-x13s-gen-1-type-21bx-21by) or use unofficialy [`fwupd`](https://github.com/fwupd/firmware-lenovo/issues/439)

###### Things done

- [x] Tested the changes in your own NixOS Configuration
- [x] Tested the changes end-to-end by using your fork of `nixos-hardware` and
      importing it via `<nixos-hardware>` or Flake input




Diff:
diff --git a/README.md b/README.md
index 29e22f7a0..273ca628a 100644
--- a/README.md
+++ b/README.md
@@ -294,6 +294,7 @@ See code for all available configurations.
 | [Lenovo ThinkPad X1 Extreme Gen 3](lenovo/thinkpad/x1-extreme/gen3)               | `<nixos-hardware/lenovo/thinkpad/x1-extreme/gen3>`      |
 | [Lenovo ThinkPad X1 Extreme Gen 4](lenovo/thinkpad/x1-extreme/gen4)               | `<nixos-hardware/lenovo/thinkpad/x1-extreme/gen4>`      |
 | [Lenovo ThinkPad X1 Nano Gen 1](lenovo/thinkpad/x1-nano/gen1)                     | `<nixos-hardware/lenovo/thinkpad/x1-nano/gen1>`         |
+| [Lenovo ThinkPad X13s](lenovo/thinkpad/x13s)                                      | `<nixos-hardware/lenovo/thinkpad/x13s>`                 |
 | [Lenovo ThinkPad X13 Yoga](lenovo/thinkpad/x13/yoga)                              | `<nixos-hardware/lenovo/thinkpad/x13/yoga>`             |
 | [Lenovo ThinkPad X13 Yoga (3th Gen)](lenovo/thinkpad/x13/yoga/3th-gen)            | `<nixos-hardware/lenovo/thinkpad/x13/yoga/3th-gen>`     |
 | [Lenovo ThinkPad X13 (Intel)](lenovo/thinkpad/x13/intel)                          | `<nixos-hardware/lenovo/thinkpad/x13/intel>`            |
diff --git a/flake.nix b/flake.nix
index 629d8f71b..848265ca0 100644
--- a/flake.nix
+++ b/flake.nix
@@ -244,6 +244,7 @@
         lenovo-thinkpad-x13-amd = import ./lenovo/thinkpad/x13/amd;
         lenovo-thinkpad-x13-yoga = import ./lenovo/thinkpad/x13/yoga;
         lenovo-thinkpad-x13-yoga-3th-gen = import ./lenovo/thinkpad/x13/yoga/3th-gen;
+        lenovo-thinkpad-x13s = import ./lenovo/thinkpad/x13s;
         lenovo-thinkpad-x140e = import ./lenovo/thinkpad/x140e;
         lenovo-thinkpad-x200s = import ./lenovo/thinkpad/x200s;
         lenovo-thinkpad-x220 = import ./lenovo/thinkpad/x220;
diff --git a/lenovo/thinkpad/x13s/README.md b/lenovo/thinkpad/x13s/README.md
new file mode 100644
index 000000000..f46081852
--- /dev/null
+++ b/lenovo/thinkpad/x13s/README.md
@@ -0,0 +1,10 @@
+# Lenovo X13s
+
+[Debian](https://wiki.debian.org/InstallingDebianOn/Thinkpad/X13s)
+[PostmarketOS](https://wiki.postmarketos.org/wiki/Lenovo_ThinkPad_X13s_(lenovo-21bx))
+
+## Camera
+The MIPI camera does work, however, it's not accelerated by the ISP and therefore image processing is done on CPU.
+
+## Wifi and Bluetooth MAC addresses
+Currently they need to be set manually
diff --git a/lenovo/thinkpad/x13s/default.nix b/lenovo/thinkpad/x13s/default.nix
new file mode 100644
index 000000000..161d3891e
--- /dev/null
+++ b/lenovo/thinkpad/x13s/default.nix
@@ -0,0 +1,101 @@
+{ lib, pkgs, ... }:
+
+let
+  dtbName = "sc8280xp-lenovo-thinkpad-x13s.dtb";
+  dtb = "${pkgs.linux}/dtbs/qcom/${dtbName}";
+  # Version the dtb based on the kernel
+  dtbEfiPath = "dtbs/x13s-${pkgs.linux.version}.dtb";
+  cfg = {
+   wifiMac = "e4:65:38:52:22:a9";
+   bluetoothMac = "E4:25:18:22:44:AA";
+  };
+  inherit (lib) mkDefault;
+in
+{
+  imports = [
+    ../.
+    ../../../common/pc/laptop
+  ];
+
+  boot = {
+    loader.systemd-boot.extraFiles = {
+      "${dtbEfiPath}" = dtb;
+    };
+
+    kernelParams = mkDefault [
+      # needed to boot
+      "dtb=${dtbEfiPath}"
+
+      # jhovold recommended
+      "clk_ignore_unused"
+      "pd_ignore_unused"
+      "arm64.nopauth"
+    ];
+
+    kernelModules = mkDefault [
+      "nvme"
+      "phy-qcom-qmp-pcie"
+      "pcie-qcom"
+
+      "i2c-core"
+      "i2c-hid"
+      "i2c-hid-of"
+      "i2c-qcom-geni"
+
+      "leds_qcom_lpg"
+      "pwm_bl"
+      "qrtr"
+      "pmic_glink_altmode"
+      "gpio_sbu_mux"
+      "phy-qcom-qmp-combo"
+      "gpucc_sc8280xp"
+      "dispcc_sc8280xp"
+      "phy_qcom_edp"
+      "panel-edp"
+      "msm"
+    ];
+  };
+
+  hardware.enableRedistributableFirmware = mkDefault true;
+
+  systemd.services.bluetooth-x13s-mac = lib.mkIf (cfg.bluetoothMac != null) {
+    wantedBy = [ "multi-user.target" ];
+    before = [ "bluetooth.service" ];
+    requiredBy = [ "bluetooth.service" ];
+
+    serviceConfig = {
+      Type = "oneshot";
+      RemainAfterExit = true;
+      ExecStart = "${pkgs.util-linux}/bin/script -q -c '${pkgs.bluez}/bin/btmgmt --index 0 public-addr ${cfg.bluetoothMac}'";
+    };
+  };
+
+  # https://github.com/jhovold/linux/wiki/X13s#modem
+  networking.networkmanager.fccUnlockScripts = [
+
+    {
+      id = "105b:e0c3";
+      path = "${pkgs.modemmanager}/share/ModemManager/fcc-unlock.available.d/105b";
+    }
+  ];
+
+  # https://github.com/jhovold/linux/wiki/X13s#camera
+  services.udev.extraRules = lib.strings.concatLines (
+    [
+      ''
+        ACTION=="add", SUBSYSTEM=="dma_heap", KERNEL=="linux,cma", GROUP="video", MODE="0660"
+        ACTION=="add", SUBSYSTEM=="dma_heap", KERNEL=="system", GROUP="video", MODE="0660"
+      ''
+    ]
+    ++ (
+      if cfg.wifiMac != null then
+        [
+          ''
+            ACTION=="add", SUBSYSTEM=="net", KERNELS=="0006:01:00.0", RUN+="${pkgs.iproute2}/bin/ip link set dev $name address ${cfg.wifiMac}"
+          ''
+        ]
+      else
+        [ ]
+    )
+  );
+}


Reviews:
user: login: Mic92
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T06:46:36Z
user: login: phodina
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-23T19:24:31Z

Review comments:
diff_hunk: @@ -244,6 +244,7 @@
         lenovo-thinkpad-x13-amd = import ./lenovo/thinkpad/x13/amd;
         lenovo-thinkpad-x13-yoga = import ./lenovo/thinkpad/x13/yoga;
         lenovo-thinkpad-x13-yoga-3th-gen = import ./lenovo/thinkpad/x13/yoga/3th-gen;
+        lenovo-thinkpad-x13s = import ./lenovo/thinkpad/x13s;
path: flake.nix
user: login: Mic92
body: Please also add this to the README.md table.
created_at: 2025-04-23T06:46:36Z
author_association: MEMBER
diff_hunk: @@ -244,6 +244,7 @@
         lenovo-thinkpad-x13-amd = import ./lenovo/thinkpad/x13/amd;
         lenovo-thinkpad-x13-yoga = import ./lenovo/thinkpad/x13/yoga;
         lenovo-thinkpad-x13-yoga-3th-gen = import ./lenovo/thinkpad/x13/yoga/3th-gen;
+        lenovo-thinkpad-x13s = import ./lenovo/thinkpad/x13s;
path: flake.nix
user: login: phodina
body: Added.
created_at: 2025-04-23T19:24:31Z
author_association: NONE

PR comments:
user: login: phodina
created_at: 2025-04-13T11:12:08Z
body: Seems some issue with either SQLite database or lock file. :arrow_up: 

Looked at the starfive/visionfive how it handles the kernel for RISC-V arch and it's in mainline.

https://github.com/NixOS/nixos-hardware/blob/master/starfive/visionfive/v2/default.nix
author_association: NONE
user: login: phodina
created_at: 2025-04-18T09:21:51Z
body: So the problem is the line, had to be reverted for 24.11
```
networking.networkmanager.fccUnlockScripts
```
as on unstable it's already changed
```
networking.modemmanager.fccUnlockScripts
```
author_association: NONE