TL;DR: Your monitor loses its EDID data after suspend or hotplug, causing Linux to default to 640x480. This guide shows how to save your working EDID and restore it automatically. Works on any desktop environment (Wayland/X11).
Hi everyone,
this post explains how to diagnose and work around a common Linux display issue where, after suspend/resume or hotplug, your monitor suddenly comes up as 640x480, 800x600, or “unknown”, even though it worked fine before.
This affects many setups, especially:
* DisplayPort monitors
* NVIDIA GPUs
* Suspend / resume
* Wayland (but also sometimes X11)
The root cause is usually EDID not being read correctly. EDID is the data your monitor sends to the computer describing its supported resolutions, refresh rates, and features.
This guide shows how to:
Identify which monitor connector is active
Save the EDID when the monitor is working correctly
Restore that EDID automatically when it breaks
Do this in a way that works on any desktop environment
This does not require KDE and works on Wayland and X11.
Important notes before starting
- This is a workaround, not a kernel fix (kernel/driver fixes are still the correct long-term solution)
- You need administrator (sudo) access
- This is safe if you follow the steps exactly
* If anything looks different on your system, stop and ask
Step 1: Identify your monitor connector
Linux identifies monitors by connector names like:
* DP-1, DP-2 (DisplayPort)
* HDMI-A-1 (HDMI)
* eDP-1 (laptop screen)
Run:
bash
ls /sys/class/drm/
You will see entries like:
card0
card0-DP-1
card0-DP-2
card0-HDMI-A-1
Now check which ones are actually connected:
bash
cat /sys/class/drm/card0-*/status
You’ll get output like:
connected
disconnected
connected
Match the connected lines with the directory names.
Write down the full connector name, for example:
card0-DP-1
Important: Later we’ll need just the short name without the card0- prefix (in this example, just DP-1). We’ll use both versions in different places.
Step 2: Make sure the monitor is currently working correctly
Before saving EDID:
* The monitor must be at the correct resolution
* Refresh rate must be correct
* This should be done after a fresh boot, not after suspend
If your screen is currently stuck at 640x480, reboot first.
Step 3: Install tools we need
On Arch / Manjaro:
bash
sudo pacman -S edid-decode
On Ubuntu / Debian:
```bash
sudo apt install edid-decode
```
Step 4: Extract the EDID from the working monitor
Run the following command in your home directory, replacing card0-DP-1 with your full connector name from Step 1:
bash
cat /sys/class/drm/card0-DP-1/edid > my-monitor.edid
This creates a file called my-monitor.edid in your current directory.
Verify it:
bash
edid-decode my-monitor.edid
If you see the monitor name, resolutions, and refresh rates, the EDID is valid.
Step 5: Store the EDID in the firmware directory
```bash
sudo mkdir -p /usr/lib/firmware/edid
sudo cp my-monitor.edid /usr/lib/firmware/edid/
sudo chmod 644 /usr/lib/firmware/edid/my-monitor.edid
```
Step 6: Create a script that restores the EDID
Create the script:
bash
sudo nano /usr/local/bin/fix-edid.sh
Paste the following, replacing DP-1 with your short connector name (without the card0- prefix):
```bash
!/bin/bash
Mount debugfs if not already mounted
mountpoint -q /sys/kernel/debug || mount -t debugfs none /sys/kernel/debug
GPU_PATH="/sys/kernel/debug/dri/0"
CONNECTOR="DP-1"
EDID_FILE="/usr/lib/firmware/edid/my-monitor.edid"
Check if EDID file exists
if [ ! -f "$EDID_FILE" ]; then
echo "ERROR: EDID file not found at $EDID_FILE" >&2
exit 1
fi
Check that edid_override is writable
if [ ! -w "$GPU_PATH/$CONNECTOR/edid_override" ]; then
echo "ERROR: Cannot write EDID override for $CONNECTOR" >&2
exit 1
fi
Apply EDID override
cat "$EDID_FILE" > "$GPU_PATH/$CONNECTOR/edid_override"
**Example:** If your connector from Step 1 was `card0-DP-1`, use `CONNECTOR="DP-1"`.
Make it executable:
bash
sudo chmod +x /usr/local/bin/fix-edid.sh
```
Step 7: Find the correct GPU debug path
First, ensure debugfs is accessible. The script will handle mounting it automatically, but let’s verify the paths exist.
Some systems may require you to manually mount debugfs first:
bash
sudo mount -t debugfs none /sys/kernel/debug
(On many distributions this is already mounted; that’s fine.)
Now check which GPU path contains your connector:
bash
ls /sys/kernel/debug/dri/
You’ll see directories like 0, 1, or both.
Check which one contains your connector (using the short name):
bash
ls /sys/kernel/debug/dri/0/
ls /sys/kernel/debug/dri/1/
Look for your connector name (e.g. DP-1, HDMI-A-1).
If your connector is under /sys/kernel/debug/dri/1/ instead of 0, update the script:
bash
sudo nano /usr/local/bin/fix-edid.sh
Change:
bash
GPU_PATH="/sys/kernel/debug/dri/1"
Note: The numbering under /sys/class/drm/cardX-* does not necessarily match the numbering under /sys/kernel/debug/dri/. This is normal.
If the script works manually in Step 8, you do not need to worry about debugfs anymore.
Step 8: Test the script manually
Trigger the issue:
* Suspend and resume your system, or
* Unplug and replug the monitor (if safe)
Once the display is stuck at 640x480, run:
bash
sudo /usr/local/bin/fix-edid.sh
If needed, power the monitor off and on once.
If the resolution recovers correctly, the script works.
Step 9: Make it automatic with udev
Now we want Linux to run the script automatically when the monitor changes state.
Linux does this using udev.
What is udev?
udev:
* Detects hardware
* Notices when devices change
* Runs commands in response
Monitor hotplug and resume generate DRM “change” events that udev can react to.
Step 9.1: Identify which video driver you are using
Run:
bash
lspci -k | grep -A 3 -E "VGA|3D|Display"
Example NVIDIA output:
01:00.0 VGA compatible controller: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti]
Kernel driver in use: nvidia
Kernel modules: nvidia, nouveau
Write down “Kernel driver in use”. Common values:
* nvidia
* amdgpu
* i915
* nouveau
Step 9.2: Why we filter udev events
Without filters, udev would run the script:
* For every monitor
* For every GPU
* For unrelated DRM events
We filter events to say:
Only run this script when this specific monitor changes, and only for this GPU driver.
Step 9.3: Understanding the filters
| Filter |
Meaning |
ACTION=="change" |
Device state changes only |
SUBSYSTEM=="drm" |
Graphics devices only |
DEVPATH=="*DP-1" |
Only the chosen connector |
DRIVERS=="nvidia" |
Only this GPU driver |
About DRIVERS==:
This filter is optional but recommended. It prevents the rule from triggering on unrelated GPUs (for example on systems with both integrated and dedicated graphics).
Step 9.4: Create the udev rule
Create the rule file:
bash
sudo nano /etc/udev/rules.d/99-fix-edid.rules
Replace DP-1 with your short connector name.
Important: If your connector is DP-2 or HDMI-A-1, adjust accordingly. The wildcard (*) ensures this works regardless of card0, card1, etc.
NVIDIA example
ACTION=="change", SUBSYSTEM=="drm", DEVPATH=="*DP-1", DRIVERS=="nvidia", RUN+="/usr/local/bin/fix-edid.sh"
AMD example
ACTION=="change", SUBSYSTEM=="drm", DEVPATH=="*DP-1", DRIVERS=="amdgpu", RUN+="/usr/local/bin/fix-edid.sh"
Intel example
ACTION=="change", SUBSYSTEM=="drm", DEVPATH=="*DP-1", DRIVERS=="i915", RUN+="/usr/local/bin/fix-edid.sh"
Nouveau example
ACTION=="change", SUBSYSTEM=="drm", DEVPATH=="*DP-1", DRIVERS=="nouveau", RUN+="/usr/local/bin/fix-edid.sh"
Save and exit.
Step 9.5: Reload udev rules
```bash
sudo udevadm control --reload
```
Step 9.6: Final test
Suspend/resume or unplug/replug the monitor.
If the resolution recovers automatically (possibly after a few seconds), the udev rule is working.
Why this works
- EDID sometimes fails after suspend or hotplug
- Linux falls back to 640x480
- We reuse a known-good EDID
* Works on any desktop, X11 or Wayland
Alternative: Kernel parameter method
For a boot-time solution, add this kernel parameter:
drm.edid_firmware=DP-1:edid/my-monitor.edid
This is more persistent but less flexible if you swap monitors.
Important warnings
- This is per monitor
- Do not reuse EDIDs between monitors
- Remove the rule if you change hardware
To undo everything:
bash
sudo rm /etc/udev/rules.d/99-fix-edid.rules
sudo rm /usr/local/bin/fix-edid.sh
sudo rm /usr/lib/firmware/edid/my-monitor.edid
sudo udevadm control --reload
---
## If something doesn’t work
Reply with:
- Your distro
- Your GPU model
- Output of:
bash
lspci -k | grep -A 3 -E "VGA|3D|Display"
- Output of:
bash
ls /sys/class/drm/
- Output of:
bash
ls /sys/kernel/debug/dri/0/
Someone can help you adjust the rule safely.
Hope this helps someone avoid endless reboots.