Skip to content

About

Working Intel IPU3 hardware-ISP camera on the Google Pixel Slate (nocturne) under mainline Linux — the kernel IOMMU quirk it hinges on, plus libcamera fixes.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nocturne-ipu3-camera

Making the Intel IPU3 hardware ISP camera work on the Google Pixel Slate (board codename nocturne) under mainline Linux — both cameras, full resolution, auto‑exposure and autofocus, at near‑zero CPU.

Out of the box, mainline Linux cannot use this tablet's cameras through the hardware ISP. Worse: trying to hard‑locks the machine (no panic, physical reset required). This repo documents the full root‑cause analysis and the complete set of patches — three kernel patches and one userspace (libcamera) patch — that turn it into a working, good‑looking camera.


⚠️ The whole thing hinges on one kernel patch

Everything here depends on kernel/9204-iommu-vtd-ipu3-imgu-identity-domain.patch. Without it, the userspace work is not just useless — it hard‑locks the machine.

The staging ipu3-imgu driver bypasses the Linux DMA API. It backs its buffers with alloc_pages() / vb2_dma_sg and programs the ImgU's own internal MMU with raw physical addresses:

/* drivers/staging/media/ipu3/ipu3-mmu.c */
phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;   /* frame buffers */

/* drivers/staging/media/ipu3/ipu3-dmamap.c */
imgu_mmu_map(imgu->mmu, iovaddr, page_to_phys(pages[i]), PAGE_SIZE);

There is no dma_map_sg / dma_alloc_coherent anywhere — only dma_set_mask. So the ImgU emits physical addresses onto the PCIe bus and assumes they land in RAM 1:1. That is only valid if the device sits in an IOMMU passthrough / identity domain.

Modern kernels put PCI devices in a translated IOMMU domain by default (DMA-FQ under Intel VT‑d). On such a kernel the ImgU's physical addresses are fed to VT‑d, which has no mapping for them, and the first streaming DMA faults and hangs the bus — the "camera freeze."

9204 fixes this by forcing an identity domain for just the ImgU (8086:1919) via a per‑device quirk in intel_iommu's device_def_domain_type(), mirroring the existing per‑device IDENTMAP_AZALIA handling. The ImgU gets the passthrough it requires; every other device keeps full IOMMU protection. No iommu=pt cmdline needed.

Booting with the global iommu=pt cmdline is the blunt equivalent and is enough to prove the diagnosis, but it drops translation for every device. 9204 scopes the passthrough to the one device that needs it. See docs/01-root-cause-the-iommu-linchpin.md.

The proper long‑term fix is to port ipu3-imgu to the DMA API so it stops emitting physical addresses; until then, this quirk is what makes the hardware ISP usable at all.


Hardware

  • Device: Google Pixel Slate (board nocturne), running Linux via MrChromebox coreboot.
  • SoC camera block: Intel IPU3.
    • ipu3-cio2 — CSI‑2 receiver, PCI 00:14.3. Raw Bayer capture. Uses the DMA API correctly, so it works under a translated IOMMU. (This is the software‑ISP path — see below.)
    • ipu3-imgu — staging hardware ISP, PCI 00:05.0 (8086:1919). The hardware ISP. This is the one that hard‑locks without 9204.
  • Sensors: imx319 (front / user‑facing), imx355 (rear / world‑facing), ak7375 VCM (rear autofocus).

Developed and tested against Linux 7.1.9 (a custom build) and libcamera 0.7.0 (Ubuntu source). The patches are written against mainline source, not the custom config; the kernel mechanisms are general to any kernel with the same structure.


The full stack

Kernel — kernel/

Patch What it does
9204 IOMMU identity‑domain quirk The linchpin. Forces an identity IOMMU domain for the ImgU so its raw‑physical DMA works. Without this the ImgU hard‑locks the machine.
9202 ImgU grab‑leak fix Crash‑proofing: a failed CSS start used to leak a grabbed control, wedging the ImgU (EBUSY, and a hard lock if re‑streamed). Turns the wedge into a clean error.
9203 sensor orientation quirk coreboot ships no SSDB ACPI table, so the sensors expose no rotation/orientation. A DMI quirk supplies them (imx319 front/180°, imx355 back/0°), retiring a userspace env‑var hack.

Userspace — userspace/

A single 13‑file libcamera 0.7.0 patch (libcamera-nocturne-ipu3.patch): camera enablement (sensor helpers, IPU3‑packed Bayer unpack for the software fallback, format‑negotiation fallback, pipeline precedence, two gammaTable_ out‑of‑bounds fixes) plus five image‑quality fixes to the ipu3 IPA — exposure (VBLANK), autofocus range, a resolution/binning cap, gamma, and colour saturation. Details in docs/02-image-quality-fixes.md.


Two working configurations

The userspace patch builds two ways from one source tree:

  1. Hardware ISP (recommended, the daily driver). Build libcamera with the ipu3 pipeline handler. Uses the ImgU. Requires kernel 9204. ~0% CPU, full 3A in hardware.
  2. Software ISP (fallback, no hardware ISP). Build without the ipu3 handler; a build‑time guard then lets the generic simple pipeline drive the ipu3-cio2 receiver and debayer in software. Does not touch the ImgU, so it works even without 9204 — but costs ~85% of one CPU core.

See userspace/README.md for build/install of both.


Results

The rear imx355 — the pipe that hard‑locked the machine three times during diagnosis — now streams the hardware ISP cleanly. Representative measurements (1280×720, rear camera) as each fix landed:

Broken After IOMMU (9204) After IQ fixes
Streams without locking ✗ (hard lock) ✓ 120 fps ✓
Max advertised resolution — 1280×720 3200×1800
Exposure ceiling — 8262 µs (pinned) up to 60 ms
Digital gain (noise) in dim light — 8.1× 1.23×
CPU cost — ~0% (hardware ISP) ~0%

Full‑resolution frames resolve individual hairs and wall texture; auto‑exposure and autofocus work in normal use.


Upstreaming

Most of this is upstreamable and helps every IPU3 device, not just nocturne:

  • 9204 and the ipu3-imgu DMA‑API limitation it works around are a real, documented kernel issue.
  • The libcamera IQ fixes each close a long‑standing \todo in the ipu3 IPA — and they are all the same bug pattern: a value that is correct as a default being used as a hard limit, or a constant hardcoded where the driver/hardware could have been queried. Five separate instances. Each fix mirrors an existing in‑tree pattern (rkisp1, StillCapture, IDENTMAP_AZALIA).

Status & what's left

Working and in daily use. Remaining items are optional and lower‑impact:

  • A measured per‑sensor colour matrix (CCM) — the included saturation matrix is a calibration‑free interim; a real CCM needs a colour chart.
  • A lens‑shading (LSC) stage — the ipu3 IPA has none at all; ~17% corner falloff. Needs a new algorithm + calibration.
  • Honouring FrameDurationLimits (the last exposure \todo; dim‑light framerate floor).
  • A dedicated camera app (live preview + orientation‑aware rotation).

Credits

Root‑cause analysis, kernel patches, and libcamera fixes developed collaboratively. See docs/ for the full investigation trail — the IOMMU mechanism, the image‑quality fixes, and how to reproduce.

Licensing

The kernel patches are derivative of the Linux kernel and carry GPL‑2.0. The libcamera patch is derivative of libcamera and carries LGPL‑2.1‑or‑later. The documentation in this repository is CC‑BY‑4.0. See LICENSE.

About

Working Intel IPU3 hardware-ISP camera on the Google Pixel Slate (nocturne) under mainline Linux — the kernel IOMMU quirk it hinges on, plus libcamera fixes.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors