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.
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=ptcmdline 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. Seedocs/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.
- Device: Google Pixel Slate (board nocturne), running Linux via MrChromebox coreboot.
- SoC camera block: Intel IPU3.
ipu3-cio2— CSI‑2 receiver, PCI00: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, PCI00: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),ak7375VCM (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.
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.
The userspace patch builds two ways from one source tree:
- Hardware ISP (recommended, the daily driver). Build libcamera with the
ipu3pipeline handler. Uses the ImgU. Requires kernel 9204. ~0% CPU, full 3A in hardware. - Software ISP (fallback, no hardware ISP). Build without the
ipu3handler; a build‑time guard then lets the genericsimplepipeline drive theipu3-cio2receiver 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.
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.
Most of this is upstreamable and helps every IPU3 device, not just nocturne:
- 9204 and the
ipu3-imguDMA‑API limitation it works around are a real, documented kernel issue. - The libcamera IQ fixes each close a long‑standing
\todoin 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).
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).
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.
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.