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: add more details to the AMD VSDB
Author:  Julian Orth <[email protected]>
Date:    Thu Nov 20 16:17:44 2025 +0100

These values have been determined through reverse engineering and might
be inaccurate.

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

 utils/edid-decode/parse-cta-block.cpp | 183 +++++++++++++++++++++++++---------
 1 file changed, 137 insertions(+), 46 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/commit/?id=07632801b9d39d4fdb41a3346e74f88b16519fa2
diff --git a/utils/edid-decode/parse-cta-block.cpp 
b/utils/edid-decode/parse-cta-block.cpp
index 3783a32e9e7e..ecf32b9fbe48 100644
--- a/utils/edid-decode/parse-cta-block.cpp
+++ b/utils/edid-decode/parse-cta-block.cpp
@@ -1576,60 +1576,151 @@ static void cta_hf_sbtmdb(const unsigned char *x, 
unsigned length)
 
 static void cta_amd(const unsigned char *x, unsigned length)
 {
-       // These Freesync values are reversed engineered by looking
-       // at existing EDIDs.
-       printf("    Version: %u\n", x[0]);
+    // 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];
+       printf("    Version: %u\n", version);
 
-       // Obtained from:
-       // 
https://github.com/torvalds/linux/commit/ec8e59cb4e0c1a52d5a541fff9dcec398b48f7b4
        printf("    Feature Caps: 0x%02x\n", x[1]);
-       if (x[1] & 0x40)
-               printf("      Replay Supported\n");
-
+    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("    Minimum Refresh Rate: %u Hz\n", x[2]);
-       printf("    Maximum Refresh Rate: %u Hz\n", x[3]);
+       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 (length >= 10) {
-               // Freesync 2.x flags
-               // Bit 2 no doubt indicates if the monitor supports Local 
Dimming
-               // There are probably also bits to signal support of the
-               // FreeSync2_scRGB and FreeSync2_Gamma22 HDR display modes.
-               // I suspect bits 0 and 1.
-               printf("    Flags 2.x: 0x%02x\n", x[5]);
-               // The AMD tone mapping tutorial referred to in the URL below
-               // mentions that the Freesync HDR info reports max/min
-               // luminance of the monitor with and without local dimming.
-               //
-               // 
https://gpuopen.com/learn/using-amd-freesync-premium-pro-hdr-code-samples/
-               //
-               // So I assume that the first two luminance values are
-               // the max/min luminance of the display and the next two
-               // luminance values are the max/min luminance values when
-               // local dimming is disabled. The values I get seem to
-               // support that.
-               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[5] & 4) {
-                       // One or both bytes can be 0. The meaning of that
-                       // is unknown.
-                       printf("    Maximum luminance (without local dimming): 
%u (%.3f cd/m^2)\n",
-                              x[8], 50.0 * pow(2, x[8] / 32.0));
-                       printf("    Minimum luminance (without local dimming): 
%u (%.3f cd/m^2)\n",
-                              x[9], (50.0 * pow(2, x[8] / 32.0)) * pow(x[9] / 
255.0, 2) / 100.0);
-               } else {
-                       // These bytes are always 0x08 0x2f. If these values
-                       // represent max/min luminance as well, then these
-                       // would map to 59.460 and 0.020 cd/m^2 respectively.
-                       // I wonder if this somehow relates to SDR.
-                       printf("    Unknown: 0x%02x 0x%02x\n", x[8], x[9]);
-               }
-       }
+
+    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] >> 5 == 1;
+    bool is_oled     = x[5] >> 5 == 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);
+    }
 }
 
 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