Skip to content

ov5693 on IPU6 (Surface Pro 8): 2x-binned 1296x972 readout returns zero-byte buffers with csi2 Transfer FIFO overflow, full 2592x1944 readout works #2234

Open

Description

@Erlend2k

Summary

On a Surface Pro 8 (TGL, IPU6, ov5693 front sensor), the sensor's 2x-binned
1296x972 readout produces zero-byte buffers
and a burst of
csi2-4: Transfer FIFO overflow, while the full 2592x1944 readout works
perfectly on the same boot, same session
. The binned mode is the one every
default application asks for (GNOME Snapshot, Firefox/Chromium getUserMedia and
most WebRTC pages open at 640x480 or 720p), so the camera looks completely dead
to a user while a full-resolution cam capture reports everything is fine.

Filing this separately from the CSI2 clock-lane work in #2171, because it is a
distinct fault that survives that fix.

Environment

  • Surface Pro 8, Zorin OS 18.1
  • Kernel 6.19.8-surface-3 (linux-surface, carries 0013-cameras.patch)
  • intel_ipu6 / intel_ipu6_isys, CSI2 port 4
  • libcamera 0.7.1 (simple pipeline + software ISP), pipewire 1.0.5
  • Sensor ov5693, Bayer BGGR10

Confirmation for #2171 (clock lane), not a new finding

The MIPI_CTRL00 (register 0x4800) write from #2171 is required on this
hardware and it works. Without it, every capture at every size ended in
stream stop time out with zero bytes: the sensor streams internally but the
CSI2 D-PHY clock lane never starts, so the receiver sees nothing. With it, the
full-resolution readout delivers real frames reliably. That patch is not mine
and this is only a hardware confirmation on a Surface Pro 8, offered because the
PR needs testers.

The actual report: per-mode failure

With the clock-lane fix applied and the driver otherwise stock, capture size
decides everything (cam -c 2 --capture=3, one run per row):

Requested Sensor readout Result
2592x1944 full real frames
1920x1080 full, cropped real frames
1280x720 2x-binned 1296x972 zero-byte buffers
640x480 2x-binned 1296x972 zero-byte buffers

The failing rows log csi2-4: Transfer FIFO overflow in dmesg. The passing
rows do not depend on luck: full-resolution capture was repeated many times over
several hours without a single short buffer.

Read the sensor readout, not the requested size. Both failing rows negotiate the
same binned 1296x972 readout, and both fail; both passing rows read out the full
array. So this is a property of the binned mode, not of any particular output
resolution.

Workaround used here (a workaround, not a fix)

Two hunks in drivers/media/i2c/ov5693.c, both required together:

  1. ov5693_set_fmt(): clamp hratio and vratio to 1, 1 instead of 1, 2,
    so only the full-sensor readout can ever be selected.
  2. ov5693_enum_frame_size(): reject at fse->index > 0 instead of > 1, so
    the binned size is no longer advertised.

The second one is easy to miss and matters: if set_fmt refuses a size that
enum_frame_size still advertises, the driver lies to userspace and libcamera
negotiates a mode it can never get back.

With both applied, every requested size produces frames and the applications
work. The cost is real and users will notice it: the sensor now always reads out
the full array, so a small requested size arrives as a narrow, zoomed-in field
of view, plus the CPU cost of handling full-resolution frames for a 640x480
stream. That is why this is posted as a bug report rather than a patch.

What the real fix probably is

The binned readout changes the CSI2 line length and timing while the D-PHY link
configuration stays as computed for the full readout, which fits a receiver-side
FIFO overflow rather than a sensor-side fault. The fix is presumably the CSI2
D-PHY link timing (or the link frequency / lane rate derived for the binned
mode), after which both hunks above can be dropped.

Happy to run any test build or register dump on this hardware.

Activity

  1. luqqas96 commented on Aug 21, 2026

    @luqqas96

    Second device with this, and one data point that complicates the picture usefully.

    Surface Pro 7+, Fedora 44, kernel 6.19.8-3.surface.fc43, IPU6 8086:9a19, front
    ov5693, libcamera 0.7.1. Same fault, same shape as yours: anything that negotiates the
    2x-binned 1296x972 readout comes back with empty buffers, while the full 2592x1944 readout
    delivers frames in the same session. And the same practical consequence — every application
    asks for 640x480 or 720p, so the camera looks dead while cam at full resolution says
    everything is fine.

    Different kernel message. Where you get csi2-4: Transfer FIFO overflow, this machine
    logs intel_ipu6_isys.isys: csi2-4 error: Frame sync error on the failing captures. Two
    different receiver-side complaints for the same binned readout is probably worth noting for
    whoever chases the root cause.

    Also worth ruling out: it is not the libcamera software-ISP bug. Reproduces identically
    with LIBCAMERA_SOFTISP_MODE=cpu and =gpu.

    The complication

    A Surface Pro 7+ in #1702 / #2201 reports the binned mode working: 1296x972 SBGGR10,
    300/300 frames, ~28.7 fps, no timeout. Same model, same sensor, opposite result.

    Machine Binned 1296x972 How MIPI_CTRL00 is written libcamera
    Pro 7+ (@Sevron88) works, 300/300 frames driver patch (#2171), before each stream-on 0.7.0
    Pro 8 (this issue) zero-byte buffers driver patch (#2171) 0.7.1
    Pro 7+ (mine) empty buffers, Frame sync error userspace I2C service, written once 0.7.1 + local patch

    The most visible difference between the working setup and mine is not the machine — it is
    when 0x4800 gets written. The driver patch rewrites it on every stream-on; my
    userspace service writes it once at boot. Selecting the binned mode reprograms the sensor,
    so a register written once may simply not survive the mode switch.

    That is a hypothesis, not a result. I can test it cheaply — this machine can write any
    sensor register over I2C from userspace, no rebuild or module signing needed — and I will
    post what I get. If it holds, the binned mode may not be broken at all on some of these
    devices, and the driver-side fix here would be masking a write-ordering problem rather than
    a hardware limit. Worth knowing before the hratio/vratio clamp lands, since that clamp
    costs every user the full-resolution readout plus a software downscale.

    For reference, that cost is real: forcing the native mode on this machine runs ~12-15% of
    one core out of eight during capture, plus GPU load for the EGL debayer.

    On your two-hunk workaround: I reached the same conclusion one layer up, in libcamera's
    simple pipeline, filtering the broken binning modes out of the sensor's mode list. Your
    second hunk is the one that matters and it is easy to miss — I hit exactly that failure. If
    set_fmt refuses a size that enum_frame_size still advertises, libcamera negotiates a
    mode it can never get back and the failure moves rather than disappearing.

    If the fix does belong in the driver, I would rather have it there than in libcamera: a
    local libcamera build is what is currently keeping this machine on a version-locked package
    with no security updates.

  2. rarestache commented on Oct 7, 2026

    @rarestache

    Another Surface Pro 8 data point, and it bears on the write-timing hypothesis in the comment above: with 0x4800 written by the driver on every stream-on, the binned mode still fails here.

    Setup: Surface Pro 8 (TGL IPU6 8086:9a19, ov5693 at INT33BE, csi2-4), Fedora 43, 6.19.8-3.surface.fc43, libcamera 0.5.2 (Fedora package, simple pipeline + soft ISP), PipeWire 1.4.11. Capture via pipewiresrc.

    ov5693.ko rebuilt out of tree from v6.19.8 ov5693.c (the only ov5693.c change in 0013-cameras.patch is the OVTI5693 HID, irrelevant for INT33BE), plus a cci_write(0x4800, 0x24) immediately before the OV5693_SW_STREAM_REG write in ov5693_enable_streaming(), i.e. on every stream-on, as in the v2 upstream patch.

    Driver Requested Result
    stock 640x480 stream stop time out, 0 frames
    + 0x4800 = 0x24 at each stream-on 640x480 (binned 1296x972) 1 all-black frame, then a flood of csi2-4 error: Frame sync error (~134 suppressed per 5 s)
    + 0x4800 = 0x24 at each stream-on 1920x1080 (full readout) 40/40 frames, correct image, no csi2 errors
    + 0x24 + both hunks from this issue (hratio = vratio = 1, enum_frame_size rejects index > 0) 640x480 700+ frames, correct image, no csi2 errors

    So on this machine the binned failure is not a write-once artifact: the register is rewritten at every stream-on and the binned readout still breaks, with Frame sync error (as on @luqqas96's Pro 7+) rather than Transfer FIFO overflow.

    Not tested: 0x20 or 0x2d with the binned mode. I only tried 0x24.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions