]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Read EDID from VBIOS embedded panel info
authorTimur Kristóf <timur.kristof@gmail.com>
Tue, 28 Apr 2026 11:40:44 +0000 (13:40 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 29 Apr 2026 14:41:40 +0000 (10:41 -0400)
Some board manufacturers hardcode the EDID for the embedded
panel in the VBIOS. This EDID should be used when the panel
doesn't have a DDC.

For reference, see the legacy non-DC display code:
amdgpu_atombios_encoder_get_lcd_info()

This is necessary to support embedded connectors without DDC.

Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)")
Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364)

drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h

index e270b1d2457cebedd1c6077605e6bc1b8fb3db59..c307f42fe0b988d5d7190bc92f6e9e543f40583f 100644 (file)
@@ -1313,6 +1313,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(
        return BP_RESULT_FAILURE;
 }
 
+static enum bp_result get_embedded_panel_extra_info(
+       struct bios_parser *bp,
+       struct embedded_panel_info *info,
+       const uint32_t table_offset)
+{
+       uint8_t *record = bios_get_image(&bp->base, table_offset, 1);
+       ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
+       ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
+
+       while (*record != ATOM_RECORD_END_TYPE) {
+               switch (*record) {
+               case LCD_MODE_PATCH_RECORD_MODE_TYPE:
+                       record += sizeof(ATOM_PATCH_RECORD_MODE);
+                       break;
+               case LCD_RTS_RECORD_TYPE:
+                       record += sizeof(ATOM_LCD_RTS_RECORD);
+                       break;
+               case LCD_CAP_RECORD_TYPE:
+                       record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
+                       break;
+               case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
+                       fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
+                       if (fake_edid_record->ucFakeEDIDLength) {
+                               if (fake_edid_record->ucFakeEDIDLength == 128)
+                                       info->fake_edid_size =
+                                               fake_edid_record->ucFakeEDIDLength;
+                               else
+                                       info->fake_edid_size =
+                                               fake_edid_record->ucFakeEDIDLength * 128;
+
+                               info->fake_edid = fake_edid_record->ucFakeEDIDString;
+
+                               record += struct_size(fake_edid_record,
+                                                     ucFakeEDIDString,
+                                                     info->fake_edid_size);
+                       } else {
+                               /* empty fake edid record must be 3 bytes long */
+                               record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
+                       }
+                       break;
+               case LCD_PANEL_RESOLUTION_RECORD_TYPE:
+                       panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
+                       info->panel_width_mm = panel_res_record->usHSize;
+                       info->panel_height_mm = panel_res_record->usVSize;
+                       record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
+                       break;
+               default:
+                       return BP_RESULT_BADBIOSTABLE;
+               }
+       }
+
+       return BP_RESULT_OK;
+}
+
 static enum bp_result get_embedded_panel_info_v1_2(
        struct bios_parser *bp,
        struct embedded_panel_info *info)
@@ -1429,6 +1483,10 @@ static enum bp_result get_embedded_panel_info_v1_2(
        if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
                info->lcd_timing.misc_info.API_ENABLED = true;
 
+       if (lvds->usExtInfoTableOffset)
+               return get_embedded_panel_extra_info(bp, info,
+                       le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));
+
        return BP_RESULT_OK;
 }
 
@@ -1554,6 +1612,10 @@ static enum bp_result get_embedded_panel_info_v1_3(
                        (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
                                lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
 
+       if (lvds->usExtInfoTableOffset)
+               return get_embedded_panel_extra_info(bp, info,
+                       le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));
+
        return BP_RESULT_OK;
 }
 
index 38a77fa9b4afdef7a206c236cdc22f8572c015e7..a0f03fb67605eb50e77d1381dbf6913c93a880eb 100644 (file)
@@ -153,6 +153,10 @@ struct embedded_panel_info {
        uint32_t drr_enabled;
        uint32_t min_drr_refresh_rate;
        bool realtek_eDPToLVDS;
+       uint16_t panel_width_mm;
+       uint16_t panel_height_mm;
+       uint16_t fake_edid_size;
+       const uint8_t *fake_edid;
 };
 
 struct dc_firmware_info {