After a routine fwupd firmware update my laptop's built-in screen became very dim, even at "100%" brightness. An external monitor on the same machine looks completely normal.
Laptop: Dell Latitude 5430, Intel Iris Xe (Alder Lake, i915), internal eDP panel (AU Optronics).
OS: Ubuntu 24.04, GNOME.
Trigger: fwupd auto-flashed the Dell system BIOS from 1.36.0 to 1.39.1 (check with fwupdmgr get-history). The screen was fine before that.
What I already ruled out (none of these help):
Not a kernel regression — dim on every kernel I tried; the panel is only bright in recovery mode / with nomodeset (i.e. when i915 is not driving it).
Not gamma/ICC — xrandr Brightness 1.0, Gamma 1.0, no VCGT in the ICC profile.
Not a software brightness slider — /sys/class/backlight/intel_backlight reports brightness == actual_brightness == max_brightness (1023), yet the panel is dim.
Brightness keys only make it dimmer, never brighter.
Downgrading the BIOS is blocked: LVFS only offers 1.39.1, so fwupdmgr / GNOME Firmware cannot roll back.
How do I get the panel bright again without a BIOS downgrade?
TL;DR — The new BIOS's GOP leaves the eDP panel in DPCD/AUX backlight mode, where
"maximum" brightness is physically dim, while i915 drives brightness over the PWM pin
(as the panel's VBT requests). Panel and GPU disagree, so nothing you do to brightness has
any effect. The fix is to force the panel back into PWM-pin mode by writing DPCD
register 0x721 = 0x00, ensure the GPU PWM is on, and "re-latch" the duty cycle. A tiny
systemd service applies this on every boot.
This is confirmed working on a Latitude 5430 (BIOS 1.39.1, Ubuntu 24.04): the screen comes
up bright, the brightness slider / keys work normally again, and it stays fixed across
reboots and suspend/resume.
1. Prerequisites
sudo apt install intel-gpu-tools # provides intel_reg (fallback path)
# Secure Boot must be OFF (writing DPCD via /dev/drm_dp_aux needs an unlocked kernel).
# Check: mokutil --sb-state → "SecureBoot disabled"
2. The fix script — /usr/local/sbin/edp-backlight-fix.sh
#!/usr/bin/env bash
# Fix dim eDP backlight on Dell Latitude 5430 after BIOS 1.39.1.
# Moves the panel out of the broken DPCD/AUX mode into PWM-pin mode
# (DPCD 0x721=0x00), ensures the GPU PWM is running, and re-latches the
# duty cycle so the panel actually picks up the new mode.
set -u
log(){ logger -t edp-backlight-fix "$*"; echo "[edp-backlight-fix] $*"; }
# 1. Wait for a DP AUX char device to appear.
AUX=""
for _ in $(seq 1 30); do
for a in /dev/drm_dp_aux*; do [ -e "$a" ] && { AUX="$a"; break; }; done
[ -n "$AUX" ] && break
sleep 1
done
[ -z "$AUX" ] && { log "no /dev/drm_dp_aux*"; exit 1; }
# 2. Pick the eDP aux specifically (on eDP, DPCD 0x700 is neither 00 nor ff).
pick_edp(){
for a in /dev/drm_dp_aux*; do
[ -e "$a" ] || continue
v=$(dd if="$a" bs=1 skip=$((0x700)) count=1 2>/dev/null | xxd -p)
[ -n "$v" ] && [ "$v" != "00" ] && [ "$v" != "ff" ] && { echo "$a"; return; }
done
echo /dev/drm_dp_aux0
}
AUX=$(pick_edp)
# 3. Panel -> PWM-pin brightness control mode (DPCD 0x721 bits[1:0]=00).
printf '\x00' | dd of="$AUX" bs=1 seek=$((0x721)) conv=notrunc 2>/dev/null
# 4. Ensure GPU PWM: enable + period for ~200 Hz (0x17700).
if command -v intel_reg >/dev/null 2>&1; then
intel_reg write 0xC8250 0x80000000 >/dev/null 2>&1
intel_reg write 0xC8254 0x00017700 >/dev/null 2>&1
fi
# 5. Re-latch the duty cycle — without this the panel ignores the mode change.
BL=/sys/class/backlight/intel_backlight
if [ -d "$BL" ]; then
max=$(cat "$BL/max_brightness" 2>/dev/null || echo 1023)
cur=$(cat "$BL/brightness" 2>/dev/null || echo "$max")
echo $(( max*7/10 )) > "$BL/brightness" 2>/dev/null; sleep 0.4
echo "$cur" > "$BL/brightness" 2>/dev/null
log "aux=$AUX relatch via intel_backlight (max=$max cur=$cur)"
elif command -v intel_reg >/dev/null 2>&1; then
intel_reg write 0xC8258 0x00002580 >/dev/null 2>&1; sleep 0.4
intel_reg write 0xC8258 0x00017700 >/dev/null 2>&1
log "aux=$AUX relatch via intel_reg duty (no intel_backlight)"
else
log "aux=$AUX WARNING: no intel_backlight and no intel_reg for relatch"
fi
exit 0
Make it executable: sudo chmod +x /usr/local/sbin/edp-backlight-fix.sh
3. Run it on every boot — /etc/systemd/system/edp-backlight-fix.service
[Unit]
Description=Fix dim eDP backlight (Latitude 5430, BIOS 1.39.1 DPCD->PWM-pin)
After=display-manager.service systemd-backlight@backlight:intel_backlight.service
Wants=display-manager.service
StartLimitIntervalSec=0
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/edp-backlight-fix.sh
# Second run to override any late brightness set by the GNOME login.
ExecStartPost=/bin/sh -c 'sleep 4; /usr/local/sbin/edp-backlight-fix.sh'
RemainAfterExit=yes
[Install]
WantedBy=graphical.target
Enable it:
sudo systemctl daemon-reload
sudo systemctl enable --now edp-backlight-fix.service
4. Kernel cmdline (GRUB)
Force native backlight and disable the DPCD backlight path so the kernel drives the PWM
pin instead of fighting the script:
sudo cp -a /etc/default/grub /etc/default/grub.bak.$(date +%s)
sudo sed -i 's|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_backlight=native i915.enable_dpcd_backlight=0"|' /etc/default/grub
sudo update-grub
Reboot. The screen should come up bright on its own, and the brightness slider/keys work.
Note: i915.enable_dpcd_backlight=0 on its own does not fix it — the kernel does
not rewrite DPCD 0x721, so the explicit write in the script is still required.
Troubleshooting
- Brightness slider gone / only
acpi_video0 under /sys/class/backlight/: make sure
the cmdline says acpi_backlight=native (not video), then reboot. The script's step 5
falls back to intel_reg if intel_backlight is missing.
- Screen flashes bright then dims after login: the GNOME session re-sets brightness late;
that's what the
ExecStartPost re-run (4 s delay) is for. Increase the delay if needed.
- Rollback:
sudo cp /etc/default/grub.bak.* /etc/default/grub && sudo update-grub && sudo systemctl disable edp-backlight-fix.service.
How the root cause was found (dead ends and the actual bug)
The obvious suspects were all wrong:
- Kernel: dim on every kernel; bright only under
nomodeset/recovery (GOP driving the
panel, not i915). So it's an i915 runtime behaviour, not a kernel version regression.
- VBT (Video BIOS Table): I dumped the panel's VBT from both BIOS versions —
1.36.0 (extracted from Dell's
.exe via BIOSUtilities + a UEFI parser) and the live
1.39.1 (/sys/kernel/debug/dri/*/i915_vbt). The backlight BDB block was byte-for-byte
identical (PWM freq 200, control type 2 = "Display DDI PWM"). So i915.vbt_firmware
overrides were pointless.
The real problem is in the runtime handshake:
- The eDP panel is being controlled over DPCD/AUX:
DPCD 0x721 = 0x0a selects
"DPCD + AUX-set frequency" mode, and brightness at 0x722/0x723 = 0x3FF is the panel's
absolute maximum (bit count 0x724 = 10) — and that absolute max is physically dim.
- Meanwhile the GPU's BXT PWM controller is configured
(
0xC8250 enable, 0xC8254 period 0x17700 = 200 Hz, 0xC8258 duty), but the panel in
AUX mode ignores it — sweeping the PWM duty (100 % → 3 %) and frequency (200 Hz →
100 kHz) changed nothing.
- The new BIOS's GOP left the panel in DPCD mode, even though the VBT asks for the PWM pin
(control type 2). GPU pushes PWM, panel listens to AUX → permanent dimness.
The fix writes DPCD 0x721 = 0x00 to switch the panel to PWM-pin mode. One gotcha: the
switch only takes effect after the PWM duty is re-latched (change the value, e.g.
10 % → 100 %). That's why the script writes a different brightness and then restores it.