Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

edid-refresh-cap

A small, dependency-free Python tool to cap the advertised maximum refresh rate in a monitor's EDID so that Apple Silicon Macs (M-series) reserve less display bandwidth and can drive two external displays that would otherwise exceed the budget.

The problem

Apple Silicon Macs reserve display-controller bandwidth based on the maximum capability advertised in the EDID, not the refresh rate you actually select in System Settings. An M4 / M4 Pro can drive roughly 2× 4K@144 Hz worth of external displays. A monitor that advertises 4K@160 Hz (e.g. the INNOCN GA32V1M) consumes more than its share of that budget, so connecting a second identical display fails — only one external display works at a time.

Crucially, lowering the active refresh rate in macOS does not help — the reservation is driven by the EDID's advertised maximum, not the live mode. The only reliable lever is to edit the EDID so its advertised maximum is lower (≤120 Hz), then apply it as a per-display override (e.g. with BetterDisplay).

What the tool does

Given an EDID dump, edid_cap.py can:

  1. Drop trailing extension blocks — e.g. a DisplayID block that carries 4K@144/160 Hz detailed timings (these can't live in the base/CTA blocks because their >655 MHz pixel clock exceeds the 2-byte DTD field, so vendors stash them in a DisplayID extension).
  2. Cap the base-block "Display Range Limits" descriptor — max vertical rate and max pixel clock (a continuous-frequency display advertises a range, not just discrete modes).
  3. Cap the AMD FreeSync VSDB max refresh rate (both the legacy and the FreeSync-v3 two-byte encodings).
  4. Recompute every affected block checksum.

The Range-Limits descriptor and the AMD VSDB are located dynamically, so the tool is not hard-coded to one monitor's byte layout.

Usage

# Cap to 120 Hz (default) and drop the trailing DisplayID block:
python3 edid_cap.py edid.bin edid_capped.bin

# Keep all extension blocks, just cap the range limits / FreeSync to 144 Hz:
python3 edid_cap.py --drop-ext 0 --cap-hz 144 edid.bin edid_capped.bin

# Rename two identical units so macOS can tell them apart:
python3 edid_cap.py --name "GA32V1M Left"  left.bin  left_capped.bin
python3 edid_cap.py --name "GA32V1M Right" right.bin right_capped.bin

# Don't touch the pixel-clock limit:
python3 edid_cap.py --no-dotclock-cap edid.bin edid_capped.bin

Options:

flag default meaning
--cap-hz N 120 cap advertised max refresh to N Hz
--cap-dotclock-mhz M 1190 cap range-limits max pixel clock (1190 MHz ≈ 4K@120, blocks 4K@144+)
--drop-ext N 1 drop the last N extension blocks (0 = keep all)
--no-dotclock-cap off leave the range-limits pixel clock untouched
--name STR set the Display Product Name (≤13 chars), e.g. to label identical units

Validate

Always confirm the result with edid-decode (the authoritative VESA decoder), which explicitly flags bad checksums and out-of-range timings:

edid-decode edid_capped.bin

edid-decode is part of v4l-utils. On macOS it isn't in Homebrew; build it with the helper script:

./build-edid-decode.sh        # clones v4l-utils, builds ./edid-decode
./edid-decode edid_capped.bin

A clean run shows Checksum: 0x.. with no (should be 0x..) suffix, and no timing/range above your cap.

Applying on macOS (BetterDisplay)

  1. Settings → Displays → select the display → Custom display EDIDUpload EDID Binary → choose edid_capped.binApply EDID Now.
  2. For two identical monitors, apply per-display using BetterDisplay's per-port (Port ID) identification, and make sure each unit's override has a distinct serial number so macOS can tell them apart. (Many units already ship with distinct serials — check the base-block serial and the Display Product Serial Number descriptor before assuming they collide.)

Caveats

  • This edits the EDID bytes correctly and validly; it cannot guarantee macOS will honour the override or free the second display. Pre-reservation on Apple Silicon is a documented limitation, and some setups simply won't run dual 4K@high-refresh regardless of EDID. If a validated cap + per-port overrides + distinct serials still won't bring up the second display, treat it as a hard macOS limit.
  • No sample EDID dumps are bundled in this repo (manufacturer EDIDs may be proprietary). Use your own dump exported from BetterDisplay or edid-decode.

License

MIT — see LICENSE.

About

Cap an EDID's advertised max refresh rate so Apple Silicon Macs can drive two external displays

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages