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]
