Repository navigation
Surface Pro 6: OV5693 (front) and OV8865 (rear) cameras produce green output — ISP tuning files missing #2166
Description
DISCLAIMER: I have no idea what's going on, and I'm back with another claude-written issue. Any help for my situation is appreciated!!
Summary
Both cameras on the Surface Pro 6 are detected and enumerated correctly by
libcamera, but produce a fully green image in all applications. The root cause
is the absence of sensor-specific ISP tuning files (ov5693.yaml and
ov8865.yaml) for the IPU3 pipeline. Without them, libcamera falls back to
uncalibrated.yaml, which cannot correctly configure white balance, black
level correction, or color correction for these sensors.
Note: the wiki currently marks both OV5693 and OV8865 as ✅ for Surface Pro 6,
which is misleading — the sensors are detected, but the output is unusable.
Environment
- Device: Microsoft Surface Pro 6
- OS: Linux Mint 22 (Ubuntu 24.04 base)
- Kernel: 6.19.8-surface-3
- libcamera: v0.7.1+26-9107effd (built from source)
Current behavior
for IPA module 'ipu3', falling back to '/usr/share/libcamera/ipa/ipu3/uncalibrated.yaml'
WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8865.yaml' not found
for IPA module 'ipu3', falling back to '/usr/share/libcamera/ipa/ipu3/uncalibrated.yaml'
Both cameras enumerate correctly:
1: Internal back camera (SB.PCI0.I2C3.CAMR) [OV8865, CSI-2 receiver 0]
2: Internal front camera (SB.PCI0.I2C2.CAMF) [OV5693, CSI-2 receiver 1]
Frames are captured at ~30fps with correct byte counts (921600 bytes for
1280×720 NV12), but the image is entirely green in all applications (Zoom,
Discord, cam --capture, GStreamer pipeline to v4l2loopback).
What has been confirmed working
- Kernel detects all three sensors (OV5693, OV8865, OV7251)
dw9719VCM binds correctly (fixed in patches/6.19: cameras: add dw9719 i2c_device_id table fix #2123)- libcamera v0.7.1 enumerates both cameras
- PipeWire detects both cameras natively via the rebuilt
libspa-libcamera
plugin - Frames are streamed at correct resolution and framerate
- The green output is produced by
camitself, not by any downstream
GStreamer or v4l2loopback conversion
Root cause
The IPU3 ISP requires sensor-specific tuning files to correctly process Bayer
output. The uncalibrated.yaml fallback does not configure color correction,
white balance, or black level correction, resulting in a green image. The
Surface Pro 6's specific hardware implementation of the OV5693 and OV8865 has
never been calibrated for libcamera.
This is also reported (as a side note) in #2045 for the Surface Pro 5, and
appears to affect all IPU3-based Surface devices.
Request
Creation of ov5693.yaml and ov8865.yaml ISP tuning files for the Surface
Pro 6 hardware, to be shipped with libcamera or the linux-surface project. If
anyone has guidance on the calibration process or existing tuning files from
similar hardware that could serve as a starting point, that would be very
helpful.
Related
- Getting Cameras Working on Surface Pro 5 (Debian 13 / Trixie) #2045 — Surface Pro 5, same issue with OV8865
- SP6 camera detected, sensor ov7251 9-0060 has not format compatible with the IPU3 #1527 — Surface Pro 6, camera detection (now resolved)
- Surface Pro 6 camera not working — ipu_bridge creates no CSI-2 links #2101 — Surface Pro 6, camera enumeration regression (now resolved via patches/6.19: cameras: add dw9719 i2c_device_id table fix #2123)
- libcamera tuning documentation:
https://libcamera.org/guides/tuning-guide.html
Activity
toor11 commentedon Jun 9, 2026
We root-caused the rear-camera (ov8865) green-screen on a Surface Book 2, and at least that part of this issue is kernel-side, not a tuning-file problem —
uncalibrated.yamlis sufficient to get a live stream (the front ov5693 streams fine with it).What actually happens: the ov8865 driver writes its sensor registers only in the runtime-PM resume handler —
set_fmt()just stores the requested mode. On IPU3 platforms, ipu_bridge gives the dw9719 VCM aDL_FLAG_PM_RUNTIMEdevice link to the sensor, and on a stock desktop wireplumber holds the VCM subdev open, which pins the sensor runtime-active. After that, format changes never reach the hardware: the sensor keeps streaming the mode programmed at the last resume while ipu3-cio2 expects the newly negotiated one →frame sync error/payload length is X, received Y→ the stream stalls after a single bogus frame, which apps display forever (green in YUV).Smoking gun: with the binned mode pinned, requesting full-res fails with
payload length is 10340352, received 2585088— exactly one 1632x1224 binned frame where a 3264x2448 frame was expected. Stop wireplumber (so the sensor can suspend/resume and reprogram) and both modes stream 10/10 clean.Fix (program the negotiated mode at stream-on): submitted upstream to linux-media — https://lore.kernel.org/linux-media/[email protected]/ — and to the surface kernel as #2169. With it, the SB2 rear camera streams 40/40 frames at 30 fps through libcamera where it previously froze on frame 1.
Tuning-file quality (colors/AE being rough with
uncalibrated.yaml) is still a real, but separate, topic.N6RFM commentedon Aug 2, 2026
Confirming this also affects the Microsoft Surface Go (1st gen) with ov5693 (front) and ov8865 (rear) sensors, kernel
6.19.8-surface-3, Linux Mint.After applying the dw9719 i2c_device_id fix from PR #2123, both cameras are now detected and enumerated correctly by libcamera:
Capture works (
cam -c 2 --capture=3runs at ~30fps), and Cheese opens successfully — but all output is green. The existingov5693.yamlshipped with libcamera 0.7.0 appears to contain only algorithm stubs (Af, Agc, Awb, BlackLevelCorrection, ToneMapping) with no actual calibration data, which matches the behavior described here.A properly calibrated tuning file for ov5693 and ov8865 on Surface Go hardware would be the fix. Happy to assist with testing if anyone is working on calibration.
ma-schmitz commentedon Aug 12, 2026
Same device here (Surface Pro 6, kernel 6.19.8-surface-3) and the identical symptom, so I can say what it actually was — the diagnosis in this report points the wrong way, and I think that is worth correcting because it sends people looking for tuning files that will not help.
The green output is not a tuning problem. It is an empty buffer. I dumped the NV12 frames and they are all zeros — Y=0, U=0, V=0 — which renders as exactly that green. A frame suffering from missing white balance or colour correction would still contain image data; these contain none.
The real causes are two separate kernel bugs, both with patches already open:
i2c_device_idtable upstream in 6.19. On Surface devices the VCM is instantiated by ipu-bridge as an i2c client, so matching goes through exactly that table. Without it the driver never binds,cio2_notifier_complete()never fires, and no camera gets media links or subdev nodes. This alone leaves both cameras unusable.payload length is 2585088, received 2588672, the stream stalls after one frame and the buffers stay zero.With both applied, front and rear both work here.
Two further measurements, since the report attributes the problem to the IPA:
The tuning files change nothing.
/usr/share/libcamera/ipa/ipu3/uncalibrated.yamlcontains only a list of algorithm names with no parameters whatsoever. Copying it toov5693.yaml/ov8865.yamlsilences the warning and has no other effect.A newer libcamera does not help either. You mention building v0.7.1 from source. I measured mean frame luminance over 300 frames with a static scene: Ubuntu's stock 0.2.0 gives stdev 2.5, a self-built 0.7.2 gives 6.3. Both are stable after roughly the first 15 frames. The AGC is not the culprit.
What does remain on this device, unrelated to the above: the rear sensor sits at maximum exposure (33 ms) in indoor light because its analogue gain caps at 16x, so handheld motion blurs. That is a sensor limitation, not a bug.
luqqas96 commentedon Aug 21, 2026
Same missing tuning files on a Surface Pro 7+, with a detail that I think strengthens
the case rather than just adding a "me too".
This machine is IPU6 (Tiger Lake,
8086:9a19), not IPU3, so libcamera uses thesimplepipeline and its software ISP. The warning is the same fault through a different IPA
module:
Your Pro 6 hits it as
ipa/ipu3/uncalibrated.yaml. Same two sensors, two differentpipelines, both uncalibrated — which places the gap at the sensor level, not in either
ISP. Whoever generates
ov5693.yamlandov8865.yamlfixes both machines and bothpipelines at once.
Both cameras here do produce a usable picture rather than solid green — white balance and
exposure are just visibly poor, left to the software ISP's guesswork. So the IPU3 green
output is probably a second, separate problem stacked on top of the missing tuning files,
worth keeping distinct when someone works on this.
Agreed on the wiki point, and it applies to the Pro 7+ column too: "sensor enumerates" and
"camera is usable" are very far apart on these machines.
javon27 commentedon Aug 26, 2026
(Posting this on behalf of the user, via Claude — flagging that upfront since it's not their own typing.)
Surface Pro 7+ here too, IPU6,
simplepipeline, same two sensors. Can confirm and narrow down what luqqas96 described ("usable but visibly poor white balance") — it's specifically a red channel clipping to 255 on every frame, and I think I've found the actual root cause in libcamera 0.7.2's SoftISP.Root cause:
src/ipa/simple/algorithms/awb.cpp's AWBprocess()subtracts an 8-bit-scaleblackLevelfromstats->sum_. But for 10-bit sensors (ov5693/ov8865 both are), the stats accumulated byswstats_cpu.cpp(statsBGGR10Line0) are at native 10-bit depth (0–1023), never normalized down to 8-bit before that subtraction. That's a ~4x under-subtraction of black level in the AWB gain computation, which computes a wildly oversized red gain → red channel saturates.It's not AWB-only, though — I disabled the
Awbalgorithm entirely in the tuning file (so no white-balance gain at all is applied) and red still clips to 255/100%. SoAgcis likely affected the same way, since it consumes the same 10-bit-scale stats for its exposure/gain convergence — meaning the actual sensor exposure is probably being driven up by the same scale bug, saturating red at the raw level before any color algorithm runs.Two tuning-file-only workarounds I tried, for the record, since they're the obvious first things to reach for and neither works:
ccm: [0.40,0,0, 0,1,0, 0,0,1]to scale down R) — parses and instantiates fine, but has zero measurable effect on actual output (verified via pixel-level analysis of raw captures, byte-identical with/without). Looks like the CCM the IPA computes never actually reaches the GPU/EGL debayer shader in this pipeline — possibly worth a separate look (DebayerEGL::configure()has a[[maybe_unused]] bool ccmEnabledthat made me suspicious).blackLevelmanually to compensate the AWB's under-subtraction at the source — doesn't fix the red clipping either, and additionally crushes the other channels toward black (green channel dropped to 0 across the whole frame in my test). Net worse.So as of 0.7.2 this looks like it needs an actual source fix to
awb.cpp(and possibly the shared stats-scaling pathAgcalso reads from), not something fixable from a tuning file. Happy to test a patch against this hardware if anyone's working on one.fildunsky commentedon Aug 31, 2026
Data point from a Surface Pro 8 (OV5693 + OV13858 on IPU6,
simplepipeline handler with the CPU software ISP), since this thread has become
the place where IPU6 colour quality is discussed.
On the AWB black-level claim earlier in the thread. I checked the
0.7.0 sources: commit 07240afa12 ("libcamera: simple: Fix black level
offsets in AWB") is indeed an ancestor of the v0.7.0 tag, so that
particular bug is fixed in any current release. However there is a
second, separate unit bug in the same area which is still present in
current upstream:
SwIspStats::sum_is accumulated in native sensor units — for a 10-bitsensor the raw 0..1023 values, see
SWSTATS_ACCUMULATE_LINE_STATSwherethe
divargument normalises only the luminance histogram and not thesums. But
Awb::process()subtractscontext.activeState.blc.level,which is 8-bit (
blc.cppshifts the tuning value right by 8). So a 10-bitsensor gets a quarter of the intended black-level subtraction, and the
error grows as the scene gets darker.
I fix it by normalising the sums in
SwStatsCpu::finishFrame()by thesame factor the histogram already uses, after accumulation so no precision
is lost per pixel. Patch:
https://github.com/fildunsky/linux-surface-pro8-cameras/blob/master/patches/libcamera/softisp-stats-sums-to-8bit.patch
On tuning files for OV5693 on IPU6. They do help, a lot, but two
things caught me out and may be useful to whoever writes theirs:
libcamera 0.7's
simpleAWB is plain grey world and cannot be givenfixed gains at all — it does not read
AwbEnableorColourGains, itonly reports its own gains in metadata. Measured on a white ceiling here,
grey world sat at R/G = 0.88 (visibly green). Wiring the factory
grey-card ratios from the
.aiqbinto libipa's Bayesian AWB moved that towithin 1–2% of the factory curve. That needs a backport, since upstream's
d5d00b9c is written against a later libipa than 0.7.0 ships.
The factory calibration appears to be in pedestal-included units.
OV5693 here has a black level of 64/1023 (both the
.aiqbandlibcamera's own histogram auto-detection agree to within half a count).
Applying it is very much worth it for rendering — the darkest percentile
goes from 63 to 0, contrast rises about 40% and saturation nearly doubles,
which is exactly the "washed out" complaint. But doing so also throws the
colour badly green, identically with grey world and with the Bayesian AWB,
which suggests the colour matrices were derived without the pedestal
removed. Either the matrices need re-deriving, or the pedestal has to be
applied after the matrix rather than before. I have not solved this yet
and would be glad to hear if anyone has.
Also worth stating plainly for this thread:
simple/softisp upstream hasno sharpening and no lens shading correction algorithms at all, so
whatever the
.aiqbholds for those cannot currently be used.Full notes: https://github.com/fildunsky/linux-surface-pro8-cameras