This is an automatic generated email to let you know that the following patch 
were queued at the 
http://git.linuxtv.org/cgit.cgi/v4l-utils.git tree:

Subject: edid-decode: correct and complete AMD VSDB
Author:  Julian Orth <[email protected]>
Date:    Fri Sep 25 15:46:43 2026 +0200

This completes the work from 07632801b9d39d4fdb41a3346e74f88b16519fa2.

Sources:

- Reverse engineering of the AMD windows kernel driver.
- Patent US10706812B2 describes FreeSync 2 HDR and contains VSDB
  examples.
- Various panel manufacturers have published or leaked data sheets that
  contain annotated EDIDs. For example [1].

Changes:

- The bits in the flags bytes are now properly labeled and printed.
- Global backlight control is no longer advertised in version 3.
- x[12..=14] contain the maximum FSFT speed.
- x[4] is the MCCS VCP code.
- 3 of the flags from x[5] are no longer used in version 3.
- 1 of the flags from x[5] indicates SmartPower OLED support in version
  3.
- x[5]&0x4 was previously labeled to indicate PQ support, but that was
  incorrect and an artifact of how the windows driver converts these
  bits.
- The meaning of PQ-Interim is now documented.
- x[5]&0x20 indicates HDR10 support in version 3.
- x[15] contains another DPCD offset that can be used by the source to
  load information about the sink product and firmware checksum.

[1]: 
https://www.panelook.cn/upload/202601/NS160QDM-NZ1_Rev.P0_20241125_202601266620.pdf

Signed-off-by: Julian Orth <[email protected]>
Signed-off-by: Hans Verkuil <[email protected]>

 utils/edid-decode/parse-cta-block.cpp | 291 ++++++++++++++++++----------------
 1 file changed, 150 insertions(+), 141 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=5fe2058521b84e9b9295d785037608c396511acd
diff --git a/utils/edid-decode/parse-cta-block.cpp 
b/utils/edid-decode/parse-cta-block.cpp
index a52bc1153931..e083d968b077 100644
--- a/utils/edid-decode/parse-cta-block.cpp
+++ b/utils/edid-decode/parse-cta-block.cpp
@@ -1586,151 +1586,160 @@ static void cta_hf_sbtmdb(const unsigned char *x, 
unsigned length)
 
 static void cta_amd(const unsigned char *x, unsigned length)
 {
-    // x[00]          - major version
-    // x[01] & 0x01   - unknown, set in almost all EDIDs
-    // x[01] & 0x02   - set if x[05..=09] are valid
-    // x[01] & 0x04   - global backlight control support
-    // x[01] & 0x08   - local dimming support
-    // x[01] & 0x10   - FreeSync Panel Replay/PSR switch support
-    // x[01] & 0x20   - called the SPRS bit by AMD, related to Replay
-    // x[01] & 0x40   - FreeSync Panel Replay support
-    // x[01] & 0x80   - set if x[12..=14] are valid
-    // x[02]          - min refresh rate
-    // x[03]          - max refresh rate in versions < 3
-    // x[04]          - MCCS flags
-    // -- start of version 2 fields
-    // x[05] & 0x01   - unknown
-    // x[05] & 0x02   - unknown
-    // x[05] & 0x04   - PQ EOTF support
-    // x[05] & 0x08   - unknown
-    // x[05] & 0x10   - PQ-Interim EOTF support (unknown what that is but 
enumerated in ADL)
-    // x[05] & 0x20   - unknown but see the calculation of supported_tf below
-    // x[05] & 0xc0   - set to 1 if the display is Mini LED
-    //                  set to 2 if the display is OLED
-    // x[06]          - max luminance
-    // x[07]          - min luminance
-    // x[08]          -      if x[01] & 0x08 or display is OLED: max luminance 
without local dimming
-    //                  else if x[01] & 0x04                   : max luminance 
at min backlight
-    // x[09]          -      if x[01] & 0x08 or display is OLED: min luminance 
without local dimming
-    //                  else if x[01] & 0x04                   : min luminance 
at min backlight
-    // -- start of version 3 fields
-    // x[10]          - max refresh rate lower 8 bits in version >= 3
-    // x[11] & 0x03   - max refresh rate upper 2 bits in version >= 3
-    // x[11] & 0xfc   - unused
-    // -- end of version 3 mandatory fields, fields below will be parsed only 
if the VSDB
-    //    block is large enough
-    // x[12]          - unknown
-    // x[13]          - unknown
-    // x[14]          - unknown
-    // x[15] & 0x80   - x[15] & 0x7f is valid
-    // x[15] & 0x7f   - unknown
-    // x[16] & 0x80   - x[16] & 0x7f is valid
-    // x[16] & 0x7f   - DPCD (DisplayPort configuration data) register offset 
for
-    //                  proprietary AMD settings
-
-    if (length < 5) {
-        printf("    Data block is truncated (length = %d)\n", length);
-        return;
-    }
-
-    unsigned version = x[0];
+       // x[00]          - major version
+       // x[01] & 0x01   - FreeSync support
+       // x[01] & 0x02   - FreeSync 2 HDR support, x[05..=09] are valid
+       // x[01] & 0x04   - In version 2: Global Backlight Control support
+       //                  In version 3: Reserved
+       // x[01] & 0x08   - Local Dimming Control support
+       // x[01] & 0x10   - In version 3: FreeSync Panel Replay/PSR switch 
support
+       // x[01] & 0x20   - In version 3: Dynamic Link Rate Control support
+       // x[01] & 0x40   - In version 3: FreeSync Panel Replay support
+       // x[01] & 0x80   - In version 3: FreeSync Fast Transport (FSFT) 
support, x[12..=14] are valid
+       // x[02]          - min refresh rate
+       // x[03]          - max refresh rate in versions < 3
+       // x[04]          - MCCS VCP code
+       // -- start of version 2 fields
+       // x[05] & 0x01   - In version 2: sRGB EOTF support
+       //                  In version 3: Reserved
+       // x[05] & 0x02   - In version 2: BT.709 EOTF support
+       //                  In version 3: Reserved
+       // x[05] & 0x04   - Gamma 2.2 EOTF support
+       // x[05] & 0x08   - In version 2: Gamma 2.6 EOTF support
+       //                  In version 3: Reserved
+       //        NOTE:
+       //          The 4 EOTFs above use the native gamut and scale the input
+       //          of the inverse EOTF such that output 0 maps to 0 luminance
+       //          and output 1 maps to the max luminance.
+       // x[05] & 0x10   - In version 2:
+       //                      PQ-Interim EOTF support
+       //                      This uses the native gamut and an affine 
function is
+       //                      applied to the inverse EOTF output such that 
output 0 maps
+       //                      to the min luminance and output 1 maps to the 
max luminance.
+       //                  In version 3:
+       //                      SmartPower OLED support
+       // x[05] & 0x20   - In version 2: Reserved
+       //                  In version 3: HDR10 support
+       // x[05] & 0xc0   - In version 2: Reserved
+       //                  In version 3: set to 1 if the display is Mini LED
+       //                                set to 2 if the display is OLED
+       //                                value 3 is reserved
+       // x[06]          - max luminance
+       // x[07]          - min luminance
+       // x[08]          -      if x[01] & 0x08 or display is OLED: max 
luminance without local dimming
+       //                  else if x[01] & 0x04                   : max 
luminance at min backlight
+       // x[09]          -      if x[01] & 0x08 or display is OLED: min 
luminance without local dimming
+       //                  else if x[01] & 0x04                   : min 
luminance at min backlight
+       // -- start of version 3 fields
+       // x[10]          - max refresh rate lower 8 bits in version >= 3
+       // x[11] & 0x03   - max refresh rate upper 2 bits in version >= 3
+       // x[11] & 0xfc   - unused
+       // -- end of version 3 mandatory fields, fields below will be parsed 
only if the VSDB
+       //    block is large enough
+       // x[12..=14]     - FSFT maximum pixel clock in little-endian kHz.
+       // x[15] & 0x80   - x[15] & 0x7f is valid
+       // x[15] & 0x7f   - DPCD (DisplayPort configuration data) register 
offset for
+       //                  additional display information. (Base = 0x403)
+       // x[16] & 0x80   - x[16] & 0x7f is valid
+       // x[16] & 0x7f   - DPCD (DisplayPort configuration data) register 
offset for
+       //                  eDP display features handshake. (Base = 0x380)
+
+       if (length < 5) {
+               printf("    Data block is truncated (length = %d)\n", length);
+               return;
+       }
+
+       unsigned version = x[0];
        printf("    Version: %u\n", version);
 
-       printf("    Feature Caps: 0x%02x\n", x[1]);
-    bool hdr_fields_valid = false;
-    bool supports_local_dimming = false;
-    bool has_global_backlight_control = false;
-    if (version > 1) {
-        hdr_fields_valid = x[1] & 0x02;
-        has_global_backlight_control = x[1] & 0x04;
-        supports_local_dimming = x[1] & 0x08;
-        if (has_global_backlight_control)
-            printf("      Global Backlight Control Supported\n");
-        if (supports_local_dimming)
-            printf("      Local Dimming Supported\n");
-        if (version > 2) {
-            // Obtained from:
-            // 
https://github.com/torvalds/linux/commit/ec8e59cb4e0c1a52d5a541fff9dcec398b48f7b4
-            if (x[1] & 0x40)
-                printf("      FreeSync Panel Replay Supported\n");
-        }
-    }
-
-    unsigned short max_refresh_rate;
-    if (version > 2 && length > 0xb) {
-        max_refresh_rate = (x[0xb] & 3) << 8 | x[0xa];
-    } else {
-        max_refresh_rate = x[3];
-    }
+       printf("    Flags 1: 0x%02x\n", x[1]);
+       if (x[1] & 0x01)
+               printf("      FreeSync Supported\n");
+       if (x[1] & 0x02 && version > 1)
+               printf("      FreeSync 2 HDR Supported\n");
+       if (x[1] & 0x04 && version == 2)
+               printf("      Global Backlight Control Supported\n");
+       if (x[1] & 0x08 && version > 1)
+               printf("      Local Dimming Supported\n");
+       if (x[1] & 0x10 && version > 2)
+               printf("      Panel Replay/PSR Switch Supported\n");
+       if (x[1] & 0x20 && version > 2)
+               printf("      Dynamic Link Rate Control Supported\n");
+       if (x[1] & 0x40 && version > 2)
+               printf("      Panel Replay Supported\n");
+       if (x[1] & 0x80 && version > 2)
+               printf("      FreeSync Fast Transport Supported\n");
+
+       unsigned short max_refresh_rate;
+       if (version > 2 && length > 11) {
+               max_refresh_rate = (x[11] & 3) << 8 | x[10];
+       } else {
+               max_refresh_rate = x[3];
+       }
        printf("    Minimum Refresh Rate: %u Hz\n", x[2]);
        printf("    Maximum Refresh Rate: %u Hz\n", max_refresh_rate);
-       // Freesync 1.x flags
-       // One or more of the 0xe6 bits signal that the VESA MCCS
-       // protocol is used to switch the Freesync range
-       printf("    Flags 1.x: 0x%02x%s\n", x[4],
-              (x[4] & 0xe6) ? " (MCCS)" : "");
-
-    if (version < 2)
-        return;
-    if (length < 10) {
-        printf("    Data block is truncated (length = %d)\n", length);
-        return;
-    }
-
-    printf("    Flags 2.x: 0x%02x\n", x[5]);
-
-    if (!hdr_fields_valid)
-        return;
-
-    const unsigned TF_PQ2084         = 0x0004;
-    const unsigned TF_LINEAR_0_125   = 0x0020;
-    const unsigned TF_GAMMA_22       = 0x0080;
-
-    const unsigned CS_BT2020         = 0x0008;
-
-    // the calculation of supported_tf is a bit weird because it doesn't 
correspond to
-    // the description in the comment at the start of the function. but this 
is what ADL
-    // (AMD Display Library) reports
-    unsigned supported_tf = 0;
-    unsigned supported_cs = 0;
-    bool supports_hdr10 = x[5] & 0x34;
-    if (supports_hdr10) {
-        supported_tf |= TF_LINEAR_0_125 | TF_PQ2084;
-        supported_cs |= CS_BT2020;
-    }
-    if (x[5] & 0x04)
-        supported_tf |= TF_GAMMA_22;
-
-    if (supported_tf & TF_PQ2084)
-        printf("      ST 2084 (PQ) EOTF Supported\n");
-    if (supported_tf & TF_LINEAR_0_125)
-        printf("      Linear EOTF (Windows scRGB, 0.0 - 125.0) Supported\n");
-    if (supported_tf & TF_GAMMA_22)
-        printf("      Gamma 2.2 EOTF Supported\n");
-
-    if (supported_cs & CS_BT2020)
-        printf("      BT.2020 Gamut Supported\n");
-
-    bool is_mini_led = x[5] >> 6 == 1;
-    bool is_oled     = x[5] >> 6 == 2;
-    if (is_mini_led)
-        printf("      Display is Mini LED\n");
-    if (is_oled)
-        printf("      Display is OLED\n");
-
-    printf("    Maximum luminance: %u (%.3f cd/m^2)\n",
-           x[6], 50.0 * pow(2, x[6] / 32.0));
-    printf("    Minimum luminance: %u (%.3f cd/m^2)\n",
-           x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 2) / 100.0);
-    if (supports_local_dimming || is_oled || has_global_backlight_control) {
-        const char *type = "minimum backlight";
-        if (supports_local_dimming || is_oled)
-            type = "without local dimming";
-        printf("    Maximum luminance (%s): %u (%.3f cd/m^2)\n",
-               type, x[8], 50.0 * pow(2, x[8] / 32.0));
-        printf("    Minimum luminance (%s): %u (%.3f cd/m^2)\n",
-               type, x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 255.0, 2) 
/ 100.0);
-    }
+
+       if (x[4] != 0)
+               printf("    MCCS VCP Code: 0x%02x\n", x[4]);
+
+       if (version < 2)
+               return;
+       if (length < 10) {
+               printf("    Data block is truncated (length = %d)\n", length);
+               return;
+       }
+
+       printf("    Flags 5: 0x%02x\n", x[5]);
+       if (version >= 3) {
+               if (x[5] >> 6 == 1)
+                       printf("      Display is Mini LED\n");
+               if (x[5] >> 6 == 2)
+                       printf("      Display is OLED\n");
+               if (x[5] & 0x10)
+                       printf("      SmartPower OLED Supported\n");
+       }
+       if (x[1] & 0x02) {
+               if (x[5] & 0x01 && version < 3)
+                       printf("      sRGB EOTF Supported\n");
+               if (x[5] & 0x02 && version < 3)
+                       printf("      BT.709 EOTF Supported\n");
+               if (x[5] & 0x04)
+                       printf("      Gamma 2.2 EOTF Supported\n");
+               if (x[5] & 0x08 && version < 3)
+                       printf("      Gamma 2.6 EOTF Supported\n");
+               if (x[5] & 0x10 && version < 3)
+                       printf("      PQ-Interim EOTF Supported\n");
+               if (x[5] & 0x20 && version >= 3)
+                       printf("      ST 2084 (PQ) EOTF Supported\n");
+
+               printf("    Maximum luminance: %u (%.3f cd/m^2)\n",
+                      x[6], 50.0 * pow(2, x[6] / 32.0));
+               printf("    Minimum luminance: %u (%.3f cd/m^2)\n",
+                      x[7], (50.0 * pow(2, x[6] / 32.0)) * pow(x[7] / 255.0, 
2) / 100.0);
+               if (x[1] & 0x08 || (x[5] >> 6 == 2 && version > 2) || (x[1] & 
0x04 && version == 2)) {
+                       const char *type = "minimum backlight";
+                       if (x[1] & 0x08 || (x[5] >> 6 == 2 && version > 2))
+                               type = "without local dimming";
+                       printf("    Maximum luminance (%s): %u (%.3f cd/m^2)\n",
+                              type, x[8], 50.0 * pow(2, x[8] / 32.0));
+                       printf("    Minimum luminance (%s): %u (%.3f cd/m^2)\n",
+                              type, x[9], (50.0 * pow(2, x[8] / 32.0)) * 
pow(x[9] / 255.0, 2) / 100.0);
+               }
+       }
+
+       if (version < 3)
+               return;
+
+       if (length > 14 && x[1] & 0x80) {
+               unsigned khz = (unsigned)x[12] | ((unsigned)x[13] << 8) | 
((unsigned)x[14] << 16);
+               printf("    FreeSync Fast Transport maximum pixel clock: %u 
kHz\n", khz);
+       }
+
+       if (length > 15 && x[15] & 0x80)
+               printf("    Additional Sink Information Address: 0x%x\n", 0x403 
+ (x[15] & 0x7f));
+
+       if (length > 16 && x[16] & 0x80)
+               printf("    eDP Display Features Handshake Address: 0x%x\n", 
0x380 + (x[16] & 0x7f));
 }
 
 static std::string display_use_case(unsigned char x)
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to