Skip to content

Instantly share code, notes, and snippets.

@icq4ever
Last active July 16, 2026 22:37
Show Gist options
  • Select an option

  • Save icq4ever/e89811a42465a64902840979d4d3dcef to your computer and use it in GitHub Desktop.

Select an option

Save icq4ever/e89811a42465a64902840979d4d3dcef to your computer and use it in GitHub Desktop.
IPU6 Camera Fix on Linux (ThinkPad X1 Nano Gen 2)

IPU6 Camera Fix on Linux (ThinkPad X1 Nano Gen 2)

Environment

  • Device: Lenovo ThinkPad X1 Nano Gen 2
  • CPU: Intel Core i7-1280P (Alder Lake, 12th Gen)
  • Camera ISP: Intel IPU6
  • OS: EndeavourOS (Arch-based)
  • Kernel: 6.19 (tested), 6.18 LTS
  • Desktop: Hyprland (Wayland)

Problem

The built-in camera is not recognized properly in browsers or applications. v4l2-ctl --list-devices shows the camera as ipu6 with 32 /dev/video* entries, but none of them are usable standard V4L2 devices. Firefox shows dozens of identical ipu6 entries in camera selection and none work.

Root cause: Intel IPU6 requires a proprietary HAL (Hardware Abstraction Layer) and GStreamer plugin that bridges the raw IPU6 device to a standard V4L2 loopback device that applications can use.


Solution

Step 1: Install AUR packages

yay -S intel-ipu6-dkms-git intel-ipu6-camera-hal-git intel-ipu6-camera-bin icamerasrc-git v4l2loopback-dkms

Note: intel-ipu6-camera-hal-git and icamerasrc-git will likely fail to build with GCC 14+ due to -Werror being hardcoded in CMakeLists.txt. See the fix below.

Step 2: Fix build errors (GCC 14+/15 -Werror issue)

For each failing package, patch the CMakeLists.txt before building:

# For intel-ipu6-camera-hal-git
cd ~/.cache/yay/intel-ipu6-camera-hal-git/src/ipu6-camera-hal
sed -i 's/-Werror//g' CMakeLists.txt
cd ~/.cache/yay/intel-ipu6-camera-hal-git
makepkg -si --noextract

# For icamerasrc-git (if it also fails)
cd ~/.cache/yay/icamerasrc-git/src/icamerasrc
sed -i 's/-Werror//g' CMakeLists.txt
cd ~/.cache/yay/icamerasrc-git
makepkg -si --noextract

Step 3: Add user to video group

sudo usermod -aG video $USER
newgrp video

Step 4: Configure automatic module loading at boot

# Load modules at boot
sudo tee /etc/modules-load.d/ipu6.conf << 'EOF'
intel_ipu6_psys
v4l2loopback
EOF

# Set v4l2loopback options
sudo tee /etc/modprobe.d/v4l2loopback.conf << 'EOF'
options v4l2loopback devices=1 video_nr=100 card_label="built-in camera" exclusive_caps=1
EOF

Step 5: Create systemd service for the GStreamer bridge

sudo tee /etc/systemd/system/ipu6-camera.service << 'EOF'
[Unit]
Description=IPU6 Camera Bridge
After=multi-user.target

[Service]
ExecStart=gst-launch-1.0 icamerasrc device-name=0 ! video/x-raw,format=NV12,width=1280,height=720 ! videoconvert ! video/x-raw,format=YUY2 ! v4l2sink device=/dev/video100
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now ipu6-camera.service

Step 6: Reboot and verify

reboot

After reboot:

v4l2-ctl --list-devices
# Should show "built-in camera (platform:v4l2loopback-100): /dev/video100"

Browser Compatibility

Browser Result
Firefox ❌ Shows 32 identical ipu6 entries, none work
Brave ✅ Shows built-in camera correctly, works
Chromium ✅ Should work (Chromium-based)
Chrome ✅ Should work (Chromium-based)

Use a Chromium-based browser for camera access on this hardware.


Notes

  • This fix applies to any Intel Alder Lake / Tiger Lake / Meteor Lake laptop with an IPU6 camera ISP on Arch-based distros.
  • The GStreamer pipeline must be running for /dev/video100 to be available — the systemd service handles this automatically.
  • intel_ipu6_psys must be loaded before the GStreamer bridge starts; the modules-load.d config handles this.
  • Tested working with: Jitsi Meet (Brave).

Migrating to the Mainline Stack (Recommended for Kernel 6.16+)

The proprietary stack above stops building on kernel 6.16+ because Intel's out-of-tree DKMS repository no longer tracks upstream kernel API changes. The mainline path replaces it with libcamera's software ISP (SoftISP) — no DKMS, no proprietary blobs, no GStreamer relay.

Stack comparison

Old (proprietary):

OV2740 -> IPU6 ISYS -> IPU6 PSYS (out-of-tree) -> intel-ipu6-camera-hal -> icamerasrc -> v4l2loopback -> Apps

New (mainline):

OV2740 -> IPU6 ISYS (in-tree since 6.10) -> libcamera SoftISP -> PipeWire -> Apps

Trade-off: image quality is slightly lower (no per-pixel lens shading correction), but it works with mainline kernels and survives updates.


Step 1: Remove old packages

sudo pacman -Rns intel-ipu6-dkms-git intel-ipu6-camera-hal-git \
  intel-ipu6-camera-bin icamerasrc-git v4l2loopback-dkms

Also remove the boot configs and systemd service created earlier:

sudo rm /etc/modules-load.d/ipu6.conf
sudo rm /etc/modprobe.d/v4l2loopback.conf
sudo systemctl disable --now ipu6-camera.service
sudo rm /etc/systemd/system/ipu6-camera.service

Step 2: Install the new stack

sudo pacman -S libcamera libcamera-ipa pipewire-libcamera gst-plugin-libcamera libcamera-tools

Step 3: Reboot and verify

reboot

After reboot:

lsmod | grep -E "ipu6|ov2740|ivsc"
# Should show: intel_ipu6_isys, intel_ipu6, ipu_bridge, ivsc_csi, ivsc_ace, ov2740

cam --list
# Should show: "Internal front camera"

If cam --list shows nothing, confirm the user is in the video group:

sudo usermod -aG video $USER
# Log out and back in

Step 4: Optional — OV2740 tuning file

Improves color accuracy slightly (avoids green tint from uncalibrated defaults):

sudo tee /usr/share/libcamera/ipa/simple/ov2740.yaml << 'EOF'
# SPDX-License-Identifier: CC0-1.0
%YAML 1.1
---
version: 1
algorithms:
  - BlackLevel:
  - Awb:
  - Adjust:
  - Agc:
EOF

Step 5: Optional — digital gain udev rule (indoor lighting)

The OV2740's analogue gain range can be insufficient indoors. This sets 2x digital gain at probe time:

sudo tee /etc/udev/rules.d/99-ov2740-digital-gain.rules << 'EOF'
SUBSYSTEM=="video4linux", KERNEL=="v4l-subdev*", ATTR{name}=="ov2740*", \
    ACTION=="add", RUN+="/usr/bin/v4l2-ctl -d /dev/$kernel --set-ctrl=digital_gain=2048"
EOF

Step 6: Browser configuration

Brave / Chrome — add to ~/.config/brave-flags.conf (or chrome-flags.conf):

--enable-features=WaylandWindowDecorations,WebRTCPipeWireCapturer,WebRtcPipeWireCamera

Firefox — go to about:config and set:

media.webrtc.camera.allow-pipewire = true

Step 7: Suspend/resume fix

Camera fails after S3 sleep on kernel 6.16+. Workaround:

sudo tee /usr/lib/systemd/system-sleep/ipu6-suspend.sh << 'EOF'
#!/bin/sh
case "$1" in
    pre)  modprobe -r ov2740 intel_ipu6_isys intel_ipu6 ;;
    post) modprobe intel_ipu6 ;;
esac
EOF
sudo chmod +x /usr/lib/systemd/system-sleep/ipu6-suspend.sh

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment