10.3. The e-ink software stack (Onyx EPDC)¶
The display on the Note Air5 C is not driven by a normal Android graphics stack.
The MSM DRM/KMS display driver is not built (# CONFIG_DRM_MSM is not set — the
DRM core is compiled in, but nothing binds the panel through it), and the display
is instead an Onyx software EPD controller (EPDC): a kernel framebuffer
driver that composes grayscale/colour update regions, looks up the E-Ink waveform
for the current temperature, and pushes frames through the SoC display interface
to the panel’s timing controller. This page documents that stack from userspace
down to the built-in kernel driver’s interface. The register-level internals
of that driver — the Lattice-FPGA TCON command/flash protocol, the EPDC update
engine, the EPD-PMIC and front-light register maps, and the full function
catalogue, all recovered by static disassembly — are in
E-ink driver internals (register-level, from the kernel). The hardware side — the DPU/DSI block, the
LF-CPNX EPD-FPGA, and the panel power rails — is in Display pipeline — DSI transport to the color e-ink TCON; the
FPGA control GPIOs and the front-light enables are in Pin control — TLMM and the PMIC GPIOs.
Everything here is from the decompressed kernel Image (artifacts/kernel)
and artifacts/boot_a/kernel_config.txt, plus the userspace pieces extracted
from system_a.img / vendor_a.img. No code was executed.
10.3.1. Architecture at a glance¶
Onyx app / framework
│ update request: Surface::transferEpdc(rect + waveform_mode)
▼ (via patched libgui.so — android::EpdcWrapper)
SurfaceFlinger (Onyx-patched)
│ mergeByMode → onyx_epdc_screenRefresh →
│ ioctl(/dev/ebc, SET_EBC_SEND_UPDATE = 0x700c, hwc_epdc_llist[])
▼
/dev/ebc ── ioctl ──► CONFIG_FB_ONYX_SOFTWARE_EPDC (built-in kernel driver)
│ • builds per-update LUTs from the waveform
│ • temperature-compensated waveform lookup
▼
MSM SDE / DSI intf (TCON-sync mode: MDP_FB_FLAG_SYNC_TCON)
│
▼
LF-CPNX EPD-FPGA (TCON) ──► 10.3" colour E-Ink panel
(see /display/panel)
side channels (NOT in the frame-submit path):
• /dev/onyx/listener (FIFO) → libonyx_epd_listener.so → Java onEpdEvent()
— EPD *event notifications* up to the framework; issues no ioctl
• libonyx_neo_dither.so (dithering) / libonyx_cfa.so (RGBW) — bitmap
pre-processors run before submission; no /dev/ebc access
The key architectural fact is that the SoC’s own display hardware (the SDE/DPU
and a DSI interface) is still used, but only as a pixel transport into the
e-ink TCON. The DTB carries the SDE/DSI nodes and puts the DSI link into TCON
mode (onyx,tcon-mode-support); that hardware-side evidence is documented in
Display pipeline — DSI transport to the color e-ink TCON. On the kernel side the transport shows up as a
TCON-synchronised path — sde_hw_intf_enable_timing_engine_tcon,
MDP_FB_FLAG_SYNC_TCON, dsi tcon_mode_support — and the EPDC is configured
with CONFIG_ONYX_EPDC_TCON_TYPE_LCDIF and CONFIG_ONYX_EPDC_SEND_MODE_VIDEO
(its generic “LCDIF video” send path mapped onto that DSI/SDE intf). The actual
electrophoretic timing is done by the LF-CPNX FPGA acting as the panel TCON.
10.3.2. The kernel driver (CONFIG_FB_ONYX_SOFTWARE_EPDC)¶
The EPDC is built into the kernel, not a module — there is no epdc.ko in
/vendor/lib/modules. (The one display-related module present, lcd.ko, is
the generic upstream drivers/video/backlight/lcd.c LCD-class helper, a
dependency, not the EPD driver.) The driver registers a framebuffer —
fb%d: onyx_epdc frame buffer, using %dK of video memory — and the character
device /dev/ebc.
Relevant build-time options (kernel_config.txt):
Option |
Meaning |
|---|---|
|
the software EPD controller itself |
|
drive the panel through the LCDIF/display-interface path (here the MSM SDE/DSI intf), not a dedicated hardware EBC |
|
frames are streamed as video to the TCON |
|
the waveform is a firmware blob, sourced from the kernel’s built-in firmware (see The waveform) |
|
the display buffer is RGBA (colour panel; see Colour (CFA / RGBW)) |
|
the handwriting buffer is ION memory — the low-latency pen path |
|
segmented / partial-region updates |
|
registered as an MFD; panel power via the regulator framework |
10.3.2.1. The /dev/ebc ioctl interface¶
Userspace drives the panel entirely through ioctl on /dev/ebc. The
ioctl command set, the update-request struct, the named update modes/schemes
(A2, REGAL/GU, CFA, dither, handwrite, merge/snapshot) and the .wbf
waveform file format are documented once, in The /dev/ebc interface: ioctls, update modes, and the waveform format, since the
kernel driver internals (E-ink driver internals (register-level, from the kernel)) and this userspace-facing page both
need the same facts.
10.3.3. The waveform¶
Every update is temperature-compensated (userspace supplies temp, the
driver selects the matching per-temperature LUT). The waveform blob’s
identity, its CONFIG_EXTRA_FIRMWARE build-in, and the header/temperature-
band/LUT-tree layout are documented once in The /dev/ebc interface: ioctls, update modes, and the waveform format, which also
covers the TCON firmware and panel configs built in alongside it — including
why that makes the e-ink path’s firmware effectively below userspace despite
being served by an ordinary built-in kernel driver.
10.3.4. Colour (CFA / RGBW)¶
The Note Air5 C is a colour device: a colour-filter-array (Kaleido-class) layer over the panel. The colour handling shows up at three levels:
kernel: the
cfa_modeupdate path and the RGBA display buffer (CONFIG_ONYX_EPDC_DISPLAY_BUF_PIXEL_FORMAT_RGBA);userspace:
libonyx_cfa.so(aColorUtilsimplementation with red/green/blue/white/gray accessors and an…toRgbwBitmapconversion — the panel’s subpixels are RGBW), andlibonyx_neo_dither.sofor the dithering that colour/gray e-ink requires.
10.3.5. Front-light¶
The front-light is two LM3630A LED drivers (a warm-white and a cold-white
string; their enable GPIOs — gpio11 / gpio73 — are in Pin control — TLMM and the PMIC GPIOs). It is
driven by Onyx’s own LM3630A driver, CONFIG_ONYX_BACKLIGHT=y +
CONFIG_ONYX_BACKLIGHT_LM3630A=y — note the mainline
CONFIG_BACKLIGHT_LM3630A is explicitly off. It exposes four backlight
class devices, chmod’d for the framework by init.onyx.rc:
sysfs node |
Role |
|---|---|
|
raw warm-LED channel (one LM3630A) |
|
raw cold/white-LED channel (the other LM3630A) |
|
combined brightness abstraction |
|
combined colour-temperature abstraction (warm↔cold blend) |
So the user-facing “brightness” and “warm/cool” sliders map to
onyx_bl_br / onyx_bl_ct, which the driver decomposes into the two raw
LM3630A channels.
10.3.6. Userspace glue (init + libraries)¶
/vendor/etc/init/hw/init.onyx.rc wires the interfaces the framework uses:
creates the FIFO
/dev/onyx/listener(0666,system) — the pipe thelibonyx_epd_listener.soevent listener reads and forwards to the framework (it issues no/dev/ebcioctl; see The Onyx/Boox platform layer);chmod 0666 /dev/ebc(on thechargertrigger too, so the charging / sleep screen can be drawn);mounts
/onyxconfig(theonyxconfigpartition, Partition map and checksums) and itsmmkvkey-value store used by the Onyx config service;exposes
/sys/onyx_misc/*control knobs:captp_disable(capacitive touch),stylus_disable,hall_ctl(cover magnet),wacom_pm(pen power),key_control, andonyx_active_pen/usi_{enable,haptic_type, haptic_strength}(USI active-pen with haptics).
The Onyx display/input libraries in /system/lib64:
Library |
Role |
|---|---|
|
EPD event listener — reads the |
|
dithering for gray/colour e-ink |
|
colour-filter-array / RGBW colour processing |
|
low-latency pen/touch input reader (feeds the ION handwriting buffer) |
10.3.7. Touch and pen¶
The panel’s input side is multi-vendor at build time — the kernel enables Parade
(CONFIG_TOUCHSCREEN_ONYX_PARADE + …CYTTSP5/6), Focaltech
(…ONYX_FTS), Elan, Istaric and Wacom drivers, and three fingerprint vendors
(CONFIG_ONYX_FINGERPRINT_{CHIPSAILING,FORTSENSE,MICROARRAY}) — but this unit
ships a Parade capacitive controller (pt_tp@24, PIP2 protocol; firmware
in Firmware-blob inventory (the payloads)) and a Wacom EMR digitiser (wacom@09, with
CONFIG_ONYX_WACOM_FW_UPDATE and USI active-pen support). The controllers,
their IRQ/reset/power GPIOs and wakeup routing are in Pin control — TLMM and the PMIC GPIOs;
/sys/wacom_ts/{caldata,rawdata} expose pen calibration.
10.3.8. Scope boundary¶
This page covers the userspace services and the built-in kernel EPDC driver interface; the ioctl/waveform contract is in The /dev/ebc interface: ioctls, update modes, and the waveform format, the register-level driver internals — the Lattice ECP5 FPGA TCON command set, the LUT engine, and the EPD-PMIC/LM3630A register maps — are in E-ink driver internals (register-level, from the kernel), and the display hardware — the LF-CPNX EPD-FPGA, panel power sequencing and the boot splash — is in Display pipeline — DSI transport to the color e-ink TCON. The Onyx Android framework above this layer (the note/handwriting engine, the launcher’s refresh-mode policy) is application-layer and out of scope.
10.3.9. Provenance¶
- Source:
artifacts/kernel(built-inonyx_epdcdriver strings: TCON-sync intf,a2_enhance/gu_regal/cfa_mode/ dither tokens),artifacts/boot_a/kernel_config.txt(CONFIG_FB_ONYX_SOFTWARE_EPDCandCONFIG_ONYX_EPDC_*/CONFIG_ONYX_BACKLIGHT_*/CONFIG_EXTRA_FIRMWAREoptions),system_a.img(waveform/eink_waveform.wbf,libonyx_epd_listener.so,libonyx_cfa.so,libonyx_neo_dither.so,libonyx_pen_touch_reader.so),vendor_a.img(etc/init/hw/init.onyx.rc,lib/modules/lcd.ko).- Method:
ext4 images read read-only with
7z; kernel read withstrings/xxd; module identity from.modinfo. No code executed.- Cross-refs:
The /dev/ebc interface: ioctls, update modes, and the waveform format (ioctls, update modes, waveform format), E-ink driver internals (register-level, from the kernel) (register-level driver internals), Display pipeline — DSI transport to the color e-ink TCON (DPU/DSI + EPD-FPGA hardware), Pin control — TLMM and the PMIC GPIOs (EPD-FPGA control GPIOs, front-light enables, touch/pen pins), Firmware-blob inventory (the payloads) (touch firmware, and the CONFIG_EXTRA_FIRMWARE discussion), Partition map and checksums (the
onyxconfigpartition).