8.8 KiB
Display and brightness
Start after platform and memory. Collect the firmware GOP base, size, dimensions, stride, pixel format and reserved-memory range. Identify the panel, display controller, backlight controller and their power owners.
Use driver build integration to connect initialization, archive recipes and the OS ABI, then run this page's hardware checks.
Sources and interfaces
These links identify reviewed source revisions. Match interfaces to the selected
SoC, component and OS versions. Files in UniXNU-sheng provide board integration
examples.
| Implementation | Source | What to read and implement |
|---|---|---|
| OS display interface | NativeLegacyDisplay.cpp, OriginalMobileFramebufferABI.h | Provider methods, request layouts and selected MobileFramebuffer ABI |
| Frame ownership | NativeGOPWire.h, NativeGOPPresenter.cpp | NGPPresent, NGPSwap, NGPComplete: buffer bounds and swap retirement |
| Brightness implementation | AppleARMBacklight.cpp, GeniI2c.h | OS properties and geni_i2c_start_write/read, event and timeout handling |
| Timing reference | DisplayTimingProbe.cpp | Target controller counters and refresh measurement |
1. Establish firmware scanout
Build the integrated UEFI firmware. Confirm that its menu displays correctly. Compare GOP geometry and framebuffer bounds with the firmware memory map and board DTS. Preserve the active scanout allocation through kernel handoff.
Expected result: a stable firmware image with correct colors and dimensions. Resolve this before enabling the XNU presentation backend.
2. Adapt the XNU display backend
Read GopFramebuffer and its NativeLegacyDisplay.cpp,
NativeGOPPresenter.cpp and NativeGOPWire.h. It consumes PE_current_console
and integrates with the selected MobileFramebuffer and IOSurface ABI.
In the sheng package,
inspect LegacyDisplayProbe.cpp and DisplayTimingProbe.cpp. The device's
scripts/build-gop-legacy-display.py qualifies ABI methods against a prelinked
candidate before producing the late display archive. Supply the matching
candidate and audit inputs listed in build inputs.
- Select GopFramebuffer and the display archive recipe, preserving its dependencies.
- Enable the recipe's kernel configuration and initialization caller. sheng uses
CONFIG_XNU_NATIVE_LEGACY_DISPLAY=yand itsoffline-legacy-*arguments. - Check pixel layout, row stride, allocation size and cache handling in CPU presentation. Confirm that a known frame reaches the display.
- Check swap completion and IOSurface lifetime before enabling GPU presentation.
- Adapt timing reads to the target display controller. sheng's
sheng-dpu=1samples the SM8550 DPU and dual-DSI counters throughDisplayTimingProbe.cpp. Set refresh policy from the observed panel mode.sheng-vsync=120is sheng's requested timing value.
For the NativeGOPWire.h path, query mode/geometry first and validate each
present buffer's size and stride. In GPU handoff, track the pending frame by
NGPSwap.sequence and return NGPComplete with that sequence after copying.
Retain the source frame and IOSurface until the swap completes, and complete
the corresponding error path on timeout or failure.
Expected result: XNU publishes the display, presents frames and completes swaps. Record requested refresh and measured frame timing separately.
The 24A446 adapter supplies the default surface through the original IOSurfaceRoot
factory and validates its backing memory and geometry before transferring ownership
to the display family. The family's create_default_fb_surface() slot returns void;
its residual return register is not an object pointer. A captured 300-second boot
completed three swaps without a kernel panic and displayed the Apple logo.
Home-screen startup remains unverified; capture the display-server and SpringBoard
wait chains before treating a stationary logo as a framebuffer transfer failure.
Read the display pipes
Before changing what the display fetches, read how firmware left it.
DisplayTimingProbe.cpp does this on sheng:
| Argument | Reads |
|---|---|
sheng-dpu=2 |
VIG 0 and 1 source, size, format and fetch settings; CTL 0 state; the tear check of both interfaces; the display streams in the apps SMMU |
sheng-dpu=3 |
Also rewrites each pipe's current address and times the CTL flush latch |
On sheng both VIG pipes fetch one 32-bit physical address, the right pipe from its own source x, and a flush latches within 5.4 ms without a start because the panel refreshes by itself. The display context bank starts with translation off.
Direct scanout (sheng-dpu-scanout=2) is experimental and off by default: it
gives the display bank a stage 1 window (ShengUfs) and points the pipes at the
compositor's surfaces. Any failure falls back to the GPU copy.
The window's TCR2 sets the sign extension field (SEP, bits 17:15) to 7, as
arm-smmu does for AArch64 contexts; with SEP 0 an address with bit 31 set faults
at level 0. The compositor submits a swap when its command buffer is scheduled,
not when the GPU finished it, so the display driver flips only after the GPU
wrote everything handed to it before the swap arrived (the Adreno driver exports
the newest and the completed fence). Without that wait the pipes scan a surface
the GPU is still writing and the panel flickers. The boot log row
[direct scanout] shows flips, mapped surfaces, latch times and the time the
flips waited for the GPU. The framebuffer must be 8-bit BGRA.
3. Identify the brightness transport
Select the target's I2C, DSI-command or PWM transport and its brightness encoding.
AppleARMBacklight.cpp provides an OS-service example for KTZ8866 controllers;
GeniI2c.h defines the GENI transfer state machine used by that example.
Before reuse, record the target's controller count, register encoding, brightness range, I2C engine, slave address, pins, clocks, interrupts and power sequence. For a DSI-command or PWM backlight, implement that transport and its level encoding behind the OS-facing brightness service.
4. Adapt and enable brightness
- Update the board's engine mappings, clock votes and interrupt routing. sheng's GENI path adopts firmware-loaded engine code and timing; verify that handoff or implement the target's initialization sequence.
- Implement the target controller's level encoding, write and readback. Match the number of controllers and update order to the panel's wiring.
- For the GENI example, call
geni_i2c_prepare, start a read/write, feed interrupt status togeni_i2c_eventand callgeni_i2c_timeoutwhen its deadline expires. Complete or cancel the transfer before starting the next one. Keep service requests on the work loop and inspect failures before enabling fades. - Match
IODisplayParametersbrightness limits andbacklight-controlto the selected OS ABI. The service accepts brightness andFadePeriodproperties. - Build the service and its registration wrapper. sheng's display recipe does
both;
sheng-backlight=1enables its probe.
From the resolved target tree, locate these integration points:
rg -n 'kSeA|kSeB|kSpi|kMaxLevel|backlight-control|FadePeriod' kits/sheng/AppleARMBacklight.cpp
rg -n 'backlight|GeniI2c' scripts/build-gop-legacy-display.py
Use the equivalent kit path for the new board. Rebuild the kernel, payload and boot image through Building.
Expected result: minimum, middle and maximum settings produce corresponding
readback and visible levels; fades complete; timeout counters remain stable.
On sheng, native_backlight_stats records publication, requests, readback,
interrupts and failures. Verify UI brightness changes as a separate step from
raw controller writes.
Next step
Record display and brightness results separately, then continue with touch and buttons.