Backlight: port ANA38401 smart-dimming (5-level snap, washed-out lows, glitches) #12

Open
opened 2026-08-21 16:33:38 +00:00 by kit · 0 comments
Owner

The panel backlight has three related defects, all from the same root cause: our ana38401 driver hardcodes 5 factory gamma anchors and snaps to the nearest, instead of computing per-level gamma the way Android does.

Symptoms (all observed)

  1. Brightness jumps between ~5 stages instead of fading smoothly.
  2. Low-brightness colours look washed out — the tone curve is wrong at low luminance.
  3. Visible glitches on the screen while dragging the brightness slider.

Root cause

This DDI has no DCS brightness command (0x51). Android drives it with a smart-dimming engine that, for every brightness level, computes a fresh 33-byte gamma table + AOR + ELVSS by interpolating between a few MTP-calibrated anchor points:

  • drivers/gpu/drm/msm/samsung/ANA38401_AMSA05RB06/ss_dsi_smart_dimming_*.c (~2283 lines — the gamma math)
  • .../ss_dsi_interpolation_*.c (~606 lines — interpolation between anchors)
  • .../ss_dsi_panel_*.c (~855 lines)

Our panel-samsung-ana38401.c has ana38401_br_levels[] with 5 entries; ana38401_bl_update_status() picks the nearest. So:

  • (1) is the missing interpolation — the intermediate gamma tables don't exist in the panel (they're computed), so we can't just "add levels".
  • (2) is gamma accuracy — a single hardcoded low anchor can't provide the nonlinear per-subpixel compensation low-luminance AMOLED needs. This is exactly what smart dimming fixes.

(3) is separable and smaller

ana38401_send_brightness() sends the update as a sequence of DCS writes (AID 0x90, seven 0xb0/0xb2 mid pairs, ELVSS, 34-byte 0x83 gamma, 0xb2 key) with no frame sync, no TE gate, no lock. Dragging the slider fires this repeatedly, async to refresh, so the panel latches partial gamma mid-frame → glitches. Downstream gates brightness on ss_event_frame_update (frame boundary). Frame-syncing / serialising the update is a much smaller fix that would kill the glitch even before smart dimming lands — worth doing first.

Plan (Option B — the proper fix, chosen 2026-08-21)

  1. First, cheap win: serialise the brightness command sequence and gate it to a frame boundary (or at least a mutex + one flush), fixing symptom (3) independently.
  2. Port smart dimming: bring ss_dsi_smart_dimming + ss_dsi_interpolation into the DRM panel driver. It reads the panel MTP (factory gamma) and computes gamma/AOR/ELVSS per level. Expose a full 0–255 (or finer) backlight.
  3. Verify tone/colour at low, mid, HBM against the factory anchors; watch for non-monotonic luminance.

Risk / handling

~3000-line port of gamma math on a historically fragile panel; a wrong table can black the screen. Do it with the U-Boot serial console reachable (gts6l-reboot console) and SD autoboot in place so a bad build is a reboot, not a brick — same rule as #10. Multi-session.

(Pragmatic Option A — interpolate only AOR+ELVSS between the 5 anchors, ~50 lines — was considered and rejected in favour of B, because it wouldn't fix the washed-out lows, which are a gamma-accuracy problem.)

Related: #10 (panel blanking) touches the same driver and the same ss_event_frame_update ordering.

The panel backlight has three related defects, all from the same root cause: our `ana38401` driver hardcodes **5 factory gamma anchors** and snaps to the nearest, instead of computing per-level gamma the way Android does. ## Symptoms (all observed) 1. **Brightness jumps between ~5 stages** instead of fading smoothly. 2. **Low-brightness colours look washed out** — the tone curve is wrong at low luminance. 3. **Visible glitches on the screen while dragging the brightness slider.** ## Root cause This DDI has **no DCS brightness command (0x51)**. Android drives it with a smart-dimming engine that, for *every* brightness level, computes a fresh 33-byte gamma table + AOR + ELVSS by interpolating between a few MTP-calibrated anchor points: - `drivers/gpu/drm/msm/samsung/ANA38401_AMSA05RB06/ss_dsi_smart_dimming_*.c` (~2283 lines — the gamma math) - `.../ss_dsi_interpolation_*.c` (~606 lines — interpolation between anchors) - `.../ss_dsi_panel_*.c` (~855 lines) Our `panel-samsung-ana38401.c` has `ana38401_br_levels[]` with **5 entries**; `ana38401_bl_update_status()` picks the nearest. So: - **(1)** is the missing interpolation — the intermediate gamma tables don't exist in the panel (they're computed), so we can't just "add levels". - **(2)** is gamma accuracy — a single hardcoded low anchor can't provide the nonlinear per-subpixel compensation low-luminance AMOLED needs. This is exactly what smart dimming fixes. ## (3) is separable and smaller `ana38401_send_brightness()` sends the update as a *sequence* of DCS writes (AID `0x90`, seven `0xb0/0xb2` mid pairs, ELVSS, 34-byte `0x83` gamma, `0xb2` key) with **no frame sync, no TE gate, no lock**. Dragging the slider fires this repeatedly, async to refresh, so the panel latches partial gamma mid-frame → glitches. Downstream gates brightness on `ss_event_frame_update` (frame boundary). **Frame-syncing / serialising the update is a much smaller fix that would kill the glitch even before smart dimming lands** — worth doing first. ## Plan (Option B — the proper fix, chosen 2026-08-21) 1. **First, cheap win:** serialise the brightness command sequence and gate it to a frame boundary (or at least a mutex + one flush), fixing symptom (3) independently. 2. **Port smart dimming:** bring `ss_dsi_smart_dimming` + `ss_dsi_interpolation` into the DRM panel driver. It reads the panel MTP (factory gamma) and computes gamma/AOR/ELVSS per level. Expose a full 0–255 (or finer) backlight. 3. Verify tone/colour at low, mid, HBM against the factory anchors; watch for non-monotonic luminance. ## Risk / handling ~3000-line port of gamma math on a historically fragile panel; a wrong table can black the screen. Do it with the **U-Boot serial console reachable** (`gts6l-reboot console`) and SD autoboot in place so a bad build is a reboot, not a brick — same rule as #10. Multi-session. (Pragmatic Option A — interpolate only AOR+ELVSS between the 5 anchors, ~50 lines — was considered and rejected in favour of B, because it wouldn't fix the washed-out lows, which are a gamma-accuracy problem.) Related: #10 (panel blanking) touches the same driver and the same `ss_event_frame_update` ordering.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kit/linux-gts6l#12
No description provided.