Skip to content
djmulder edited this page Jul 2, 2026 · 9 revisions

Hardware

Component Details
CPU Intel Core Ultra (Meteor Lake)
IPU Intel IPU6 (PCI 8086:7d19)
Front camera Sony IMX681 (SONY0681, CSI port 4, D-PHY 2-lane)
Rear camera OmniVision OV13858 (OVTID858, CSI port 0, D-PHY 4-lane)
WiFi Intel Meteor Lake PCH CNVi (iwlwifi)
Touchscreen Intel THC (intel_thc_hid)

Linux Support Status

Feature Status Notes
Front camera ✅ Working Requires DKMS modules + patched libcamera (see below)
Rear camera ✅ Working Requires DKMS modules
Touchscreen ✅ Working Requires quickspi resume hook for suspend/resume
WiFi 2.4/5GHz ✅ Working
WiFi 6GHz ⚠️ Partial iwlwifi is self-managed regulatory; 6GHz band invisible until correct country code is set at boot via NetworkManager dispatcher script (iw reg set <CC>). 2.4/5GHz unaffected.
Suspend/resume ✅ Working With surface-pro-10-buttons.service + s2idle fixes
Secure Boot ✅ Working Via sbctl with Microsoft certs
Type Cover keyboard ✅ Working
USB-C ✅ Working Standard USB-C devices work
DisplayLink dock ⚠️ Requires setup Needs evdi-dkms + displaylink-driver 6.3.0
Stylus ❓ Untested

Camera Setup

Camera support requires kernel 7.0.x and several out-of-tree components.

DKMS modules required

  • imx681 — Sony IMX681 front camera sensor driver
  • ipu-bridge-fix — D-PHY config + DMI rotation fix for both sensors
  • int3472-fix — GPIO type fix for camera power sequencing
  • ov13858-fix — Reset GPIO + clock enable for rear camera

See PR #2156 for the kernel patch set (targeting kernel 7.0). Once merged, the DKMS modules will no longer be needed for patched kernels.

libcamera

Requires patched libcamera 0.7.0. Apply against applied/0.7.0-1ubuntu2, build with --prefix=/usr:

git clone https://git.ubuntu.com/ubuntu/libcamera.git
cd libcamera
git checkout applied/0.7.0-1ubuntu2
patch -p1 << 'EOF'
diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
index e3e3e53..c738284 100644
--- a/src/ipa/libipa/camera_sensor_helper.cpp
+++ b/src/ipa/libipa/camera_sensor_helper.cpp
@@ -566,6 +566,23 @@ public:
 };
 REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258)
 
+class CameraSensorHelperImx681 : public CameraSensorHelper
+{
+public:
+	CameraSensorHelperImx681()
+	{
+		/* Black level: 64 in 10-bit >> 2 = 16 in 8-bit (IPA divides by 256) */
+		blackLevel_ = 16;
+		/* Analog gain register 0x0204 is inverted: hw code 0=16x, 960=1x.
+		 * Driver inverts: logical 0=1x (hw 960), logical 960=16x (hw 0).
+		 * Correct Sony formula with driver inversion: gain = 1024/(1024-logical_code) */
+		gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 };
+	}
+};
+REGISTER_CAMERA_SENSOR_HELPER("imx681", CameraSensorHelperImx681)
+
 class CameraSensorHelperImx283 : public CameraSensorHelper
EOF
meson setup build --prefix=/usr
sudo ninja -C build install

The CameraSensorHelperImx681 class is the only strictly required change. For better image quality (AWB colour correction, gamma tuning, AGC smoothing and oscillation lockout) apply the full patch instead: libcamera-imx681-surface-pro-10.patch

Tuning file

Create /usr/share/libcamera/ipa/simple/imx681.yaml:

%YAML 1.1
---
version: 1
algorithms:
  - BlackLevel:
      blackLevel: 64
  - Awb:
      # Static colour gains to correct IMX681's native green bias.
      # Tuned for diffuse daylight (overcast/indoor with window light).
      # These disable dynamic AWB — adjust if colours look wrong in your
      # lighting conditions: raise R to warm up, raise B to cool down.
      colourGains:
        - 1.7
        - 1.4
  - Agc:
      # Wider hysteresis reduces hunting when exposure hits ceiling.
      # Larger denominator = smaller steps = smoother but slower response.
      exposureHysteresis: 0.8
      exposureStepDenominator: 15
      # Oscillation lockout: if AGC flips direction oscillationThreshold
      # times in oscillationWindow frames, freeze for oscillationLockoutFrames.
      # Prevents visible blinking under CPU load (software ISP limitation).
      oscillationWindow: 6
      oscillationThreshold: 4
      oscillationLockoutFrames: 15
  - Adjust:
      gamma: 1.6
...

Note: the Awb colourGains and Agc tuning parameters require the full patch. With only the minimal patch, omit those sections and use defaults.

Working configuration

  • Resolution: 1920×1136 (vertical binning 2×, SCALE_M horizontal scaler)
  • Bayer phase: SBGGR10
  • D-PHY 2-lane, 380.8 MHz link frequency
  • Gain: 1×–16× (analog gain register is inverted in hardware; driver corrects)
  • ~15.85 fps, works in Teams/Firefox via PipeWire portal

Key technical findings (for developers)

  • IMX681 is D-PHY despite ACPI/ipu-bridge declaring it C-PHY (SONY0681 entry needs IPU_SENSOR_CONFIG not IPU_SENSOR_CONFIG_CPHY)
  • IPU6 firmware on Meteor Lake only accepts src=4 (CSI2_3PH_PORTA); src=6 (CPHY_PORT0) is silently rejected — do not use C-PHY firmware path
  • Full resolution (3840×2640) exceeds the STR2MMIO DMA FIFO bandwidth on 2 D-PHY lanes — 1920×1136 via binning+scaler is required for the simple pipeline; full resolution would need the IPU6 PSYS ISP pipeline
  • Analog gain register 0x0204 is inverted: hardware code 0=16×, code 960=1×; driver inverts logical→hardware mapping
  • CameraSensorHelper uses Sony formula with driver inversion: gain = 1024/(1024-logical_code) = AnalogueGainLinear{ 0, 1024, -1, 1024 }
  • Secure Boot: use sbctl with --microsoft flag; MOK enrollment via shim bootloops on this hardware — enroll keys directly via sbctl instead

Suspend/Resume

See issue #2158 and PR #2159.

Required fixes:

  • quickspi-resume.sh — reload intel_quickspi after resume to restore touchscreen
  • surface-pro-10-buttons.service — power/volume button reliability
  • i915.enable_psr2_sel_fetch=0 kernel cmdline — prevents s2idle freeze
  • 99-surface-thc0-wakeup.rules — udev rule for lid/cover wake events

Tested Distributions

Distro Kernel Status Notes
Linux Mint 22.3 7.0.0-14-generic ✅ Working Recommended
Ubuntu 26.04 7.0.0-22-generic ✅ Working Snap friction with Firefox camera portal

Clone this wiki locally