Research: A2 Waveform Mode — Kernel Transform Analysis

Research: A2 Waveform Mode — Kernel Transform Analysis

Status: Research complete. NOP patch tool ready. Blocked on test session.


Problem

TWRP requests A2 waveform mode (0x0c) for fast e-ink refresh, but the kernel’s onyx_waveform_mode_transform() converts it to GC16 (mode 2), causing slow full-refresh behavior. Kernel log confirms: waveform_mode[2] is_convert[1].


Two Display Update Paths

PathUsed byTransform applied?
/dev/ebc ioctl (0x700c)TWRP, stock recoveryYES — waveform transform table applied
onyx_epdc_set_mode() kernel symbolHWC/SurfaceFlinger (stock Android)NO — bypasses transform entirely

Stock Android A2 mode works because apps use Path 2 (via HWC), which bypasses the transform. TWRP must use Path 1 (the only option without SurfaceFlinger), so it hits the transform.


Root Cause: Transform Function

FieldValue
Functiononyx_waveform_mode_transform
Kernel offset0x427a8c
Called from0x41d410 (BL 0x427a8c inside SEND_UPDATE handler)
Waveform version in firmware0x19 (“onyx waveform sg”)
What it does to A2 (0x0c)Maps to AUTO (0xFF) → then map_auto_mode() at 0x427bc8 converts AUTO → GC16 (0x02)

Fix: NOP the Transform Call

FieldValue
Patch offset0x41d410
Original bytes0x9400299F (BL 0x427a8c)
Patched bytes0xD503201F (NOP)
EffectAll waveform modes pass through unchanged. AUTO (0xFF) still → GC16 via map_auto_mode().
Tooltools/patch-kernel-waveform-transform.py
# Extract kernel, apply patch, repack
magiskboot unpack boot.img
python3 tools/patch-kernel-waveform-transform.py kernel [--dry-run]
magiskboot repack boot.img patched-boot.img
# Flash via TWRP dd or EDL
Alternative: RET at function entry (Method 2)

Patch offset 0x427a8c (first instruction of the transform function) with 0xD65F03C0 (RET). Same effect but patches the function itself rather than the call site — affects any other callers too.


Key EPDC Ioctl Numbers

IoctlNameStatus
0x7000GET_EBC_BUFFERConfirmed
0x7001SET_EBC_SEND_BUFFERConfirmed
0x7002GET_EBC_BUFFER_INFOConfirmed
0x700cSET_EBC_SEND_UPDATEConfirmed — main update command
0x700dSET_EBC_WAIT_ALL_UPDATE_COMPLETEConfirmed
0x700eSET_EBC_CLEAR_ALL_UPDATEConfirmed
0x7014SET_EBC_GAMMA_TABConfirmed

Full 34-command ioctl dispatch table found in kernel binary at 0x41eaf8. See docs/research/a2-waveform-mode.md for complete listing.


ebc-probe Warning

⚠️ Do NOT run ebc-probe in TWRP. Even phase 1 (ioctl probe with zeroed buffers) causes kernel panic → 900E EDL dump mode. The EBC driver does not tolerate probing when SurfaceFlinger/HWC is not running. ebc-probe requires a full Android boot.

More posts